是否可以在ES6类中创建私有属性?

举个例子。 如何阻止访问instance.property?

class Something {
  constructor(){
    this.property = "test";
  }
}

var instance = new Something();
console.log(instance.property); //=> "test"

当前回答

更新:看别人的回答,这个已经过时了。

简单的回答,不,ES6类不支持私有属性。

但是你可以模仿这种行为,不将新属性附加到对象,而是将它们保存在类构造函数中,并使用getter和setter来获取隐藏的属性。注意,在类的每个新实例上重新定义getter和setter。

ES6

class Person {
    constructor(name) {
        var _name = name
        this.setName = function(name) { _name = name; }
        this.getName = function() { return _name; }
    }
}

ES5

function Person(name) {
    var _name = name
    this.setName = function(name) { _name = name; }
    this.getName = function() { return _name; }
}

其他回答

事实上,使用符号和代理是可能的。您可以使用类作用域中的符号,并在代理中设置两个陷阱:一个用于类原型,以便Reflect.ownKeys(实例)或Object。getOwnPropertySymbols不会泄露你的符号,另一个是构造函数本身,所以当调用new ClassName(attrs)时,返回的实例将被拦截,并有自己的属性符号被阻塞。 代码如下:

const Human = (function() { const pet = Symbol(); const greet = Symbol(); const Human = privatizeSymbolsInFn(function(name) { this.name = name; // public this[pet] = 'dog'; // private }); Human.prototype = privatizeSymbolsInObj({ [greet]() { // private return 'Hi there!'; }, revealSecrets() { console.log(this[greet]() + ` The pet is a ${this[pet]}`); } }); return Human; })(); const bob = new Human('Bob'); console.assert(bob instanceof Human); console.assert(Reflect.ownKeys(bob).length === 1) // only ['name'] console.assert(Reflect.ownKeys(Human.prototype).length === 1 ) // only ['revealSecrets'] // Setting up the traps inside proxies: function privatizeSymbolsInObj(target) { return new Proxy(target, { ownKeys: Object.getOwnPropertyNames }); } function privatizeSymbolsInFn(Class) { function construct(TargetClass, argsList) { const instance = new TargetClass(...argsList); return privatizeSymbolsInObj(instance); } return new Proxy(Class, { construct }); }

Reflect.ownKeys()是这样工作的:Object.getOwnPropertyNames(myObj).concat(Object.getOwnPropertySymbols(myObj))这就是为什么我们需要为这些对象设置一个陷阱。

我们可以使用getter和setter来模拟类的私有属性。

eg 1

class FootballClub {
    constructor (cname, cstadium, ccurrentmanager) {
        this.name = cname;
        this._stadium  = cstadium;  //  we will treat this prop as private and give getter and setter for this.
        this.currmanager = ccurrentmanager;
    }

    get stadium( ) {
        return this._stadium.toUpperCase();
    }

}

let club = new FootballClub("Arsenal", "Emirates" , "Arteta")
console.log(club);
//FootballClub {
//    name: 'Arsenal',
//    _stadium: 'Emirates',
//    currmanager: 'Arteta'
//  }
console.log( club.stadium ); // EMIRATES
club.stadium = "Highbury"; // TypeError: Cannot set property stadium of #<FootballClub> which has only a getter

在上面的例子中,我们没有给出stadium的setter方法,因此我们不能为它设置一个新值。在接下来的例子中,为体育场添加了一个setter

eg 2

class FootballClub {
    constructor (cname, cstadium, ccurrentmanager) {
        this.name = cname;
        this._stadium  = cstadium;  //  we will treat this prop as private and give getter and setter for this.
        this.currmanager = ccurrentmanager;
    }

    get stadium( ) {
        return this._stadium.toUpperCase();
    }

    set stadium(val) {
       this._stadium = val;
    }
}

let club = new FootballClub("Arsenal", "Emirates" , "Arteta")
console.log(club.stadium); // EMIRATES
club.stadium = "Emirates Stadium";
console.log(club.stadium); // EMIRATES STADIUM

另一种方式类似于上两个帖子

class Example {
  constructor(foo) {

    // privates
    const self = this;
    this.foo = foo;

    // public interface
    return self.public;
  }

  public = {
    // empty data
    nodata: { data: [] },
    // noop
    noop: () => {},
  }

  // everything else private
  bar = 10
}

const test = new Example('FOO');
console.log(test.foo); // undefined
console.log(test.noop); // { data: [] }
console.log(test.bar); // undefined

我现在听到的建议是使用WeakMaps来保存私人数据,以供其他看客参考。

下面是一个更清晰、有效的例子:

function storePrivateProperties(a, b, c, d) {
  let privateData = new WeakMap;
  // unique object as key, weak map can only accept object as key, when key is no longer referened, garbage collector claims the key-value 
  let keyA = {}, keyB = {}, keyC = {}, keyD = {};

  privateData.set(keyA, a);
  privateData.set(keyB, b);
  privateData.set(keyC, c);
  privateData.set(keyD, d);

  return {
    logPrivateKey(key) {
      switch(key) {
      case "a":
        console.log(privateData.get(keyA));
        break;
      case "b":
        console.log(privateData.get(keyB));
        break;
      case "c":
        console.log(privateData.get(keyC));
        break;
      case "d":
        console.log(privateData.set(keyD));
        break;
      default:
        console.log(`There is no value for ${key}`)
      }
    }
  }
}

WeakMap

IE11支持(符号不支持) hard-private(由于Object.getOwnPropertySymbols,使用符号的道具是soft-private) 看起来非常干净(不像闭包需要构造函数中的所有道具和方法)

首先,定义一个函数来包装WeakMap:

function Private() {
  const map = new WeakMap();
  return obj => {
    let props = map.get(obj);
    if (!props) {
      props = {};
      map.set(obj, props);
    }
    return props;
  };
}

然后,在类外部构造一个引用:

const p = new Private();

class Person {
  constructor(name, age) {
    this.name = name;
    p(this).age = age; // it's easy to set a private variable
  }

  getAge() {
    return p(this).age; // and get a private variable
  }
}

注意:IE11不支持class,但在示例中它看起来更简洁。