Skip to content

Instantly share code, notes, and snippets.

@trusktr
Last active November 18, 2018 09:29
Show Gist options
  • Save trusktr/3088a7a301d96f099e2a0d1aed1403a2 to your computer and use it in GitHub Desktop.
Save trusktr/3088a7a301d96f099e2a0d1aed1403a2 to your computer and use it in GitHub Desktop.
Access Modifiers 1
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