JavaScript ES6类中的私有属性

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

这是一个例子。如何防止访问instance.property

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

var instance = new Something();
console.log(instance.property); //=> "test"
AEva伽罗2020/03/16 11:37:01

Yes totally can, and pretty easily too. This is done by exposing your private variables and functions by returning the prototype object graph in the constructor. This is nothing new, but take a bit of js foo to understand the elegance of it. This way does not use global scoped, or weakmaps. It is a form of reflection built into the language. Depending on how you leverage this; one can either force an exception which interrupts the call stack, or bury the exception as an undefined. This is demonstarted below, and can read more about these features here

class Clazz {
  constructor() {
    var _level = 1

    function _private(x) {
      return _level * x;
    }
    return {
      level: _level,
      public: this.private,
      public2: function(x) {
        return _private(x);
      },
      public3: function(x) {
        return _private(x) * this.public(x);
      },
    };
  }

  private(x) {
    return x * x;
  }
}

var clazz = new Clazz();

console.log(clazz._level); //undefined
console.log(clazz._private); // undefined
console.log(clazz.level); // 1
console.log(clazz.public(1)); //1
console.log(clazz.public2(2)); //2
console.log(clazz.public3(3)); //27
console.log(clazz.private(0)); //error

泡芙阿飞2020/03/16 11:37:00

是的-您可以创建封装的属性,但是至少不能通过ES6使用访问修饰符(public | private)来完成。

这是一个简单的示例,如何使用ES6完成它:

1使用课程创建课程

2在其构造函数内部,使用let OR const保留字声明块范围变量->由于它们是块范围,因此无法从外部访问(封装)

3要允许对这些变量进行某些访问控制(设置器|获取器),可以使用以下this.methodName=function(){}语法在其构造函数中声明实例方法:

"use strict";
    class Something{
        constructor(){
            //private property
            let property="test";
            //private final (immutable) property
            const property2="test2";
            //public getter
            this.getProperty2=function(){
                return property2;
            }
            //public getter
            this.getProperty=function(){
                return property;
            }
            //public setter
            this.setProperty=function(prop){
                property=prop;
            }
        }
    }

现在让我们检查一下:

var s=new Something();
    console.log(typeof s.property);//undefined 
    s.setProperty("another");//set to encapsulated `property`
    console.log(s.getProperty());//get encapsulated `property` value
    console.log(s.getProperty2());//get encapsulated immutable `property2` value
小胖Green2020/03/16 11:37:00

取决于你问的人 :-)

似乎已纳入当前草案private最大最小类提议中未包含任何属性修饰符

但是,可能会支持 确实允许私有属性的私有名称 -并且它们可能也可以在类定义中使用。

Tom卡卡西2020/03/16 11:37:00

为了将来供其他参考者参考,我现在听到的建议是使用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}`)
      }
    }
  }
}
三千曜米亚2020/03/16 11:37:00

更新:语法更好提案正在实施中。欢迎捐款。


是的,对于对象中的作用域访问,ES6引入了Symbols

符号是唯一的,除了反射之外,您不能从外部访问任何符号(例如Java / C#中的private),但是内部可以访问符号的任何人都可以使用它进行键访问:

var property = Symbol();
class Something {
    constructor(){
        this[property] = "test";
    }
}

var instance = new Something();

console.log(instance.property); //=> undefined, can only access with access to the Symbol
村村Mandy2020/03/16 11:37:00

答案是不”。但是您可以创建对属性的私有访问,如下所示:

(关于可以在早期版本的ES6规范中使用Symbols来确保隐私的建议,但现在不再适用:https//mail.mozilla.org/pipermail/es-discuss/2014-January/035604。 htmlhttps://stackoverflow.com/a/22280202/1282216。有关符号和隐私的详细讨论,请参见:https : //curiosity-driven.org/private-properties-in-javascript

Harry2020/03/16 11:37:00

简短的答案,不,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; }
}