preface

While reading ECMAScript 6, I saw the implementation of private variables here and there, so I’ll summarize it here.

1. Agreed

implementation

class Example {
	constructor() {
		this._private = 'private';
	}
	getName() {
		return this._private
	}
}

var ex = new Example();

console.log(ex.getName()); // private
console.log(ex._private); // private
Copy the code

advantages

  1. Written in simple
  2. Debug is convenient
  3. Good compatibility

disadvantages

  1. External can be accessed and modified
  2. The language has no matching mechanism, such as a for in statement that enumerates all attributes
  3. Naming conflicts

2. The closure

Implement a

/** * implements a */
class Example {
  constructor() {
    var _private = ' ';
    _private = 'private';
    this.getName = function() {return _private}
  }
}

var ex = new Example();

console.log(ex.getName()); // private
console.log(ex._private); // undefined
Copy the code

advantages

  1. No naming conflict
  2. External access and modification are unavailable

disadvantages

  1. The constructor logic becomes complicated. Constructors are supposed to do only object initialization, but now in order to implement private variables, you have to include partial method implementations, so the code organization is a little unclear.
  2. Methods exist on instances, not prototypes, and subclasses cannot use super calls
  3. Build adds a little overhead

Realize the

/** */
const Example = (function() {
  var _private = ' ';

  class Example {
    constructor() {
      _private = 'private';
    }
    getName() {
      return_private; }}returnExample; }) ();var ex = new Example();

console.log(ex.getName()); // private
console.log(ex._private); // undefined
Copy the code

advantages

  1. No naming conflict
  2. External access and modification are unavailable

disadvantages

  1. It’s a little bit complicated to write
  2. Build adds a little overhead

3. Symbol

implementation

const Example = (function() {
    var _private = Symbol('private');

    class Example {
        constructor() {
          this[_private] = 'private';
        }
        getName() {
          return this[_private]; }}returnExample; }) ();var ex = new Example();

console.log(ex.getName()); // private
console.log(ex.name); // undefined
Copy the code

advantages

  1. No naming conflict
  2. External access and modification are unavailable
  3. No performance loss

disadvantages

  1. It’s a little bit more complicated
  2. Compatibility is ok

4. WeakMap

implementation

/** * implements a */
const _private = new WeakMap(a);class Example {
  constructor() {
    _private.set(this.'private');
  }
  getName() {
  	return _private.get(this); }}var ex = new Example();

console.log(ex.getName()); // private
console.log(ex.name); // undefined
Copy the code

You might not feel encapsulated enough if you write it this way, but you can also write it this way:

/** */
const Example = (function() {
  var _private = new WeakMap(a);// Private member storage container

  class Example {
    constructor() {
      _private.set(this.'private');
    }
    getName() {
    	return _private.get(this); }}returnExample; }) ();var ex = new Example();

console.log(ex.getName()); // private
console.log(ex.name); // undefined
Copy the code

advantages

  1. No naming conflict
  2. External access and modification are unavailable

disadvantages

  1. It’s a little tricky to write
  2. There’s some compatibility issues
  3. There is a performance cost

5. The latest proposal

class Point { #x; #y; constructor(x, y) { this.#x = x; this.#y = y; } equals(point) { return this.#x === point.#x && this.#y === point.#y; }}Copy the code

So why not just use the private field? Like this:

class Foo {
  private value;

  equals(foo) {
    return this.value === foo.value; }}Copy the code

Simply put, it is too much trouble, of course, there are performance considerations…

For example, if we use the private keyword instead of # :

class Foo {
  private value = '1';

  equals(foo) {
    return this.value === foo.value; }}var foo1 = new Foo();
var foo2 = new Foo();

console.log(foo1.equals(foo2));
Copy the code

Here we create two new instances and pass foo2 as a parameter to the instance method of foo1.

So can we get the value of foo2.value? Foo2. value is a private variable and equals is a class method of Foo. Can we get equals?

The answer is yes.

Actually this in other languages, such as Java and c + + is the same, in the class member functions can access private variables of the same kind of instance, this is because the private is in order to achieve the “foreign” of information hiding, inside the class themselves, it is not necessary to prohibit access private variables, you can also understand the limit for private variables in class as the unit, Rather than object by object, it also makes it easier for users.

Since getting the value is ok, the printed result should be true, but what if the value we pass is not an instance of Foo, but some other object?

var foo1 = new Foo();

console.log(foo1.equals({
  value: 2
}));
Copy the code

Of course, this code also works, but it’s a bit more confusing for the compiler, because the compiler doesn’t know if value is a normal or private property of Foo, so the compiler needs to make a judgment about whether foo is an instance of foo, and then fetch the value.

This also means that this judgment needs to be made every time a property is accessed, and the engine is already highly optimized around property access, which is too lazy to change, and slows down.

But there are other things to consider besides this job, such as:

  1. You must encode private keys into each lexical environment
  2. Can for in iterate over these properties?
  3. When a private property has the same name as a normal property, who blocks whom?
  4. How to prevent private property names from being detected.

Refer to this Issue for more discussion on using # instead of private.

Of course these problems can be solved, but it is a bit troublesome.

If you choose #, the implementation will have nothing to do with JavaScript object attributes, it will use the private slots approach and a new slot lookup syntax, but it will be much simpler than the private implementation.

reference

  1. How Programming Languages Evolve — Taking JS Private as an Example
  2. Exploring ES6
  3. New syntax for transjs: private attributes

ES6 series

ES6 directory address: github.com/mqyqingfeng…

ES6 series is expected to write about 20 chapters, aiming to deepen the understanding of ES6 knowledge points, focusing on the block-level scope, tag template, arrow function, Symbol, Set, Map and Promise simulation implementation, module loading scheme, asynchronous processing and other contents.

If there is any mistake or not precise place, please be sure to give correction, thank you very much. If you like or are inspired by it, welcome star and encourage the author.