Last active
November 18, 2018 09:29
-
-
Save trusktr/3088a7a301d96f099e2a0d1aed1403a2 to your computer and use it in GitHub Desktop.
Access Modifiers 1
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class Foo { | |
foo = 1 | |
protected bar = 2 | |
private baz = 3 | |
public test() { | |
// call all three of the log methods, one from each access space. | |
console.log('---- public log 2') | |
this.log() | |
console.log('---- protected log 2') | |
protected this.log() | |
console.log('---- private log 2') | |
private this.log() | |
} | |
/*public*/ log() { | |
console.log('-- foo') // -- foo | |
console.log(this.foo) // 1 | |
console.log(public this.foo) // 1 | |
console.log(protected this.foo) // undefined (foo not defined in the protected space of Foo) | |
console.log(private this.foo) // undefined (foo not defined in the private space of Foo) | |
console.log('-- bar') // -- bar | |
console.log(this.bar) // undefined (bar not defined in the public space of Foo) | |
console.log(public this.bar) // undefined (bar not defined in the public space of Foo) | |
console.log(protected this.bar) // 2 | |
console.log(private this.bar) // undefined (bar not defined in the private space of Foo) | |
console.log('-- baz') // -- baz | |
console.log(this.baz) // undefined (baz not defined in the public space of Foo) | |
console.log(public this.baz) // undefined (baz not defined in the public space of Foo) | |
console.log(protected this.baz) // undefined (baz not defined in the protected space of Foo) | |
console.log(private this.baz) // 3 | |
} | |
protected log() { | |
console.log('-- foo') // -- foo | |
console.log(this.foo) // undefined (foo not defined in the protected space of Foo) | |
console.log(public this.foo) // 1 | |
console.log(protected this.foo) // undefined (foo not defined in the protected space of Foo) | |
console.log(private this.foo) // undefined (foo not defined in the private space of Foo) | |
console.log('-- bar') // -- bar | |
console.log(this.bar) // 2 | |
console.log(public this.bar) // undefined (bar not defined in the public space of Foo) | |
console.log(protected this.bar) // 2 | |
console.log(private this.bar) // undefined (bar not defined in the private space of Foo) | |
console.log('-- baz') // -- baz | |
console.log(this.baz) // undefined (baz not defined in the protected space of Foo) | |
console.log(public this.baz) // undefined (baz not defined in the public space of Foo) | |
console.log(protected this.baz) // undefined (baz not defined in the protected space of Foo) | |
console.log(private this.baz) // 3 | |
} | |
private log() { | |
console.log('-- foo') // -- foo | |
console.log(this.foo) // undefined (foo not defined in the private space of Foo) | |
console.log(public this.foo) // 1 | |
console.log(protected this.foo) // undefined (foo not defined in the protected space of Foo) | |
console.log(private this.foo) // undefined (foo not defined in the private space of Foo) | |
console.log('-- bar') // -- bar | |
console.log(this.bar) // undefined (foo not defined in the private space of Foo) | |
console.log(public this.bar) // undefined (bar not defined in the public space of Foo) | |
console.log(protected this.bar) // 2 | |
console.log(private this.bar) // undefined (bar not defined in the private space of Foo) | |
console.log('-- baz') // -- baz | |
console.log(this.baz) // 3 | |
console.log(public this.baz) // undefined (baz not defined in the public space of Foo) | |
console.log(protected this.baz) // undefined (baz not defined in the protected space of Foo) | |
console.log(private this.baz) // 3 | |
} | |
} | |
const foo = new Foo | |
foo.test() | |
class Bar extends Foo { | |
test2() { | |
console.log('---- public log 2') | |
this.log() | |
console.log('---- protected log 2') | |
protected this.log() | |
console.log('---- private log 2') | |
private this.log() | |
} | |
} | |
const bar = new Bar() | |
bar.test() | |
/** | |
* output from bar.test() is same as above | |
*/ | |
bar.test2() | |
/** | |
* output from bar.test2(): | |
*/ | |
// ---- public log | |
// -- foo | |
// 1 (inherited from the public space of Foo) | |
// 1 (inherited from the public space of Foo) | |
// undefined (foo not defined in the protected space of Bar or Foo) | |
// undefined (foo not defined in the private space of Bar) | |
// -- bar | |
// undefined (bar not defined in the public space of Bar or Foo) | |
// undefined (bar not defined in the public space of Bar or Foo) | |
// 2 (inherited from the protected space of Foo) | |
// undefined (bar not defined in the private space of Bar) | |
// -- baz | |
// undefined (baz not defined in the public space of Bar or Foo) | |
// undefined (baz not defined in the public space of Bar or Foo) | |
// undefined (baz not defined in the protected space of Bar or Foo) | |
// undefined (baz not defined in the private space of Bar) | |
// ---- protected log | |
// -- foo | |
// undefined (foo not defined in the protected space of Bar or Foo) | |
// 1 (inherited from the public space of Foo) | |
// undefined (foo not defined in the protected space of Bar or Foo) | |
// undefined (foo not defined in the private space of Bar) | |
// -- bar | |
// 2 (inherited from the protected space of Foo) | |
// undefined (bar not defined in the public space of Bar or Foo) | |
// 2 (inherited from the protected space of Foo) | |
// undefined (bar not defined in the private space of Bar) | |
// -- baz | |
// undefined (baz not defined in the protected space of Bar or Foo) | |
// undefined (baz not defined in the public space of Bar or Foo) | |
// undefined (baz not defined in the protected space of Bar or Foo) | |
// undefined (baz not defined in the private space of Bar) | |
// ---- private log | |
// TypeError: this.log() is not a function (it is `undefined`, there's no private log method in the private space of Bar) | |
///////////////////////////////////////////////////////////////////////////////////// | |
// | |
// When in a public method, `this` refers to the "public this" | |
// When in a protected method, `this` refers to the "protected this" | |
// When in a private method, `this` refers to the "private this" | |
// | |
// Think of it as if a given `class` has two prototype chains (the public one | |
// and the protected one) and one private object which is not linked to a parent | |
// class. For any "instance" of the given class there are two instance objects | |
// and N private objects where N is the number of classes in the hierarchy that | |
// have private props or methods, one private object per class. The public | |
// instance is prototipically linked to the public prototype (this is the public | |
// object we all use today) and is accessed as `this` in public methods and | |
// `public this` in protected or private methods. The protected instance is | |
// linked to the protected prototype and is accessed as `this` inside of | |
// protected methods and `protected this` in public or private methods. Each | |
// private instance is linked to the private prototype of its respective class | |
// and is accessed as `this` in private methods of its owning class and `private | |
// this` in public or protected methods of its owning class. | |
// | |
// The shape of the `foo` and `bar` instances are visualized as follows. | |
// | |
// foo: | |
// | |
// +--"foo instance"-+ +----class Foo----+ | |
// | | | | | |
// | +---------+ | | +---------+ | | |
// | |public | | | |public | | | |
// | | foo +---------->| Foo | | | |
// | | | | | |prototype| | | |
// | +---------+ | | +---------+ | | |
// | | | | | |
// | +---------+ | | +---------+ | | |
// | |protected| | | |protected| | | |
// | | foo +---------->| Foo | | | |
// | | | | | |prototype| | | |
// | +---------+ | | +---------+ | | |
// | | | | | |
// | +---------+ | | +---------+ | | |
// | |private | | | |private | | | |
// | | foo +---------->| Foo | | | |
// | | | | | |prototype| | | |
// | +---------+ | | +---------+ | | |
// | | | | | |
// +-----------------+ +-----------------+ | |
// | |
// The value of the expression `public this` in any method of the Foo class returns the object labeled "public foo". | |
// The value of the expression `protected this` in any method of the Foo class returns the object labeled "protected foo". | |
// The value of the expression `private this` in any method of the Foo class returns the object labeled "private foo". | |
// | |
// bar: | |
// | |
// +--"bar instance"-+ +----class Bar----+ +---class Foo-----+ | |
// | | | | | | | |
// | +---------+ | | +---------+ | | +---------+ | | |
// | |public | | | |public | | | |public | | | |
// | | bar +---------->| Bar +---------->| Foo | | | |
// | | | | | |prototype| | | |prototype| | | |
// | +---------+ | | +---------+ | | +---------+ | | |
// | | | | | | | |
// | +---------+ | | +---------+ | | +---------+ | | |
// | |protected| | | |protected| | | |protected| | | |
// | | bar +---------->| Bar +---------->| Foo | | | |
// | | | | | |prototype| | | |prototype| | | |
// | +---------+ | | +---------+ | | +---------+ | | |
// | | | | | | | |
// | +---------+ | | +---------+ | | +---------+ | | |
// | |private | | | |private | | | |private | | | |
// | | bar +---------->| Bar | | | | Foo | | | |
// | | (Bar) | | | |prototype| | | |prototype| | | |
// | +---------+ | | +---------+ | | +---------+ | | |
// | | | | | ^ | | |
// | | +-----------------+ +--------|--------+ | |
// | +---------+ | | | |
// | |private | | | | |
// | | bar +--------------------------------------+ | |
// | | (Foo) | | | |
// | +---------+ | | |
// | | | |
// +-----------------+ | |
// | |
// The value of the expression `public this` in any method of the Bar or Foo classes returns the object labeled "public bar". | |
// The value of the expression `protected this` in any method of the Bar or Foo classes returns the object labeled "protected bar". | |
// The value of the expression `private this` in any method of the Bar or Foo classes returns | |
// - the object labeled "private bar (Bar)" if the method belongs to the Bar class. | |
// - the object labeled "private bar (Foo)" if the method belongs to the Foo class. | |
// | |
// ...and so on... | |
// | |
// For example | |
// | |
// a Baz class and it `baz` instance would be: | |
// | |
// baz: | |
// | |
// +--"baz instance"-+ +----class Baz----+ +---class Bar-----+ +---class Foo-----+ | |
// | | | | | | | | | |
// | +---------+ | | +---------+ | | +---------+ | | +---------+ | | |
// | |public | | | |public | | | |public | | | |public | | | |
// | | baz +---------->| Baz +---------->| Bar | | | | Foo | | | |
// | | | | | |prototype| | | |prototype| | | |prototype| | | |
// | +---------+ | | +---------+ | | +---------+ | | +---------+ | | |
// | | | | | | | | | |
// | +---------+ | | +---------+ | | +---------+ | | +---------+ | | |
// | |protected| | | |protected| | | |protected| | | |protected| | | |
// | | baz +---------->| Baz +---------->| Bar | | | | Foo | | | |
// | | | | | |prototype| | | |prototype| | | |prototype| | | |
// | +---------+ | | +---------+ | | +---------+ | | +---------+ | | |
// | | | | | | | | | |
// | +---------+ | | +---------+ | | +---------+ | | +---------+ | | |
// | |private | | | |private | | | |private | | | |private | | | |
// | | baz +---------->| Baz | | | | Bar | | | | Foo | | | |
// | | (Baz) | | | |prototype| | | |prototype| | | |prototype| | | |
// | +---------+ | | +---------+ | | +---------+ | | +---------+ | | |
// | | | | | ^ | | ^ | | |
// | +---------+ | +-----------------+ +--------|--------+ +--------|--------+ | |
// | |private | | | | | |
// | | baz +--------------------------------------+ | | |
// | | (Bar) | | | | |
// | +---------+ | | | |
// | | | | |
// | +---------+ | | | |
// | |private | | | | |
// | | baz +-----------------------------------------------------------+ | |
// | | (Foo) | | | |
// | +---------+ | | |
// | | | |
// +-----------------+ | |
// | |
// The value of the expression `public this` in any method of the Baz, Bar, or Foo classes returns the object labeled "public baz". | |
// The value of the expression `protected this` in any method of the Baz, Bar, or Foo classes returns the object labeled "protected baz". | |
// The value of the expression `private this` in any method of the Baz, Bar, or Foo classes returns | |
// - the object labeled "private baz (Baz)" if the method belongs to the Baz class. | |
// - the object labeled "private baz (Bar)" if the method belongs to the Bar class. | |
// - the object labeled "private baz (Foo)" if the method belongs to the Foo class. | |
// | |
// etc... | |
////////////////////////////////////////////////////////////////////////////////// | |
// | |
// By default the `private` modifier in `public this.foo` returns the public | |
// scope of `this` (the first item in the chain of prediod-delimited | |
// identifiers). If the expression were `private lorem.ipsum`, then it would | |
// work if `lorem` is an instance of the same class as `this` in the previous | |
// expression (just like other languages). However, if the modifier needs to be | |
// applied to a subobject, it can be called with parens: | |
// | |
private(this.parent).somePrivateProp | |
// | |
// or | |
// | |
private(this.parent)['somePrivateProp'] | |
// | |
// Imagine for example that `this` and `this.parent` are both instances of a | |
// `Node` class, and a method in `Node` wants to access the private props of | |
// `this.parent`. | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment