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

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

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

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

当前回答

我有一个解决办法,它很简单…虽然性能不是问题…但它确实有效,而且效果很好。

诀窍在于,在私有属性和函数被建立和标准化/采用之前,需要另一种解决方案,这是另一种解决方案…

class ClassPrivateProperties {
    constructor(instance) {
        const $this = instance;
        let properties = {};
        this.prop = (key, value = undefined) => {
            if (!value) {
                return properties[key];
            } else {
                properties[key] = value;
            }
        };
        this.clear = instance => {
            if ($this === instance) {
                properties = {};
                return true;
            } else {
                return false;
            }
        }
    }
}

这是一个示例用法,可以是什么(如果你使用上面的感觉自由,使它更好)

class Test {
    constructor() {
        this._privateProps = new ClassPrivateProperties(this);
    }
    property(key, value = undefined) {
        if (!value) {
            return this._privateProps.prop(key);
        } else {
            this._privateProps.prop(key, value);
        }
    }
    clear() { return this._privateProps.clear(this); }
}
const test = new test;
test.property('myKey','some value here');
console.log(test.property('myKey'));

就像我提到的,这个问题不是最好的,但它工作,使属性真正的私有。

其他回答

class Something {
  constructor(){
    var _property = "test";
    Object.defineProperty(this, "property", {
        get: function(){ return _property}
    });
  }
}

var instance = new Something();
console.log(instance.property); //=> "test"
instance.property = "can read from outside, but can't write";
console.log(instance.property); //=> "test"

我现在听到的建议是使用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}`)
      }
    }
  }
}

来这个派对很晚,但我在搜索中碰到了OP问题,所以… 是的,您可以通过将类声明包装在闭包中来拥有私有属性

这里有一个我如何在这个代码依赖中拥有私有方法的例子。在下面的代码片段中,Subscribable类有两个“私有”函数process和processCallbacks。任何属性都可以以这种方式添加,并且通过使用闭包将它们保持为私有。如果关注点被很好地分离,并且Javascript不需要通过添加更多的语法而变得臃肿,当闭包整齐地完成工作时,隐私是一个罕见的需求。

const Subscribable = (function(){

  const process = (self, eventName, args) => {
    self.processing.set(eventName, setTimeout(() => processCallbacks(self, eventName, args)))};

  const processCallbacks = (self, eventName, args) => {
    if (self.callingBack.get(eventName).length > 0){
      const [nextCallback, ...callingBack] = self.callingBack.get(eventName);
      self.callingBack.set(eventName, callingBack);
      process(self, eventName, args);
      nextCallback(...args)}
    else {
      delete self.processing.delete(eventName)}};

  return class {
    constructor(){
      this.callingBack = new Map();
      this.processing = new Map();
      this.toCallbacks = new Map()}

    subscribe(eventName, callback){
      const callbacks = this.unsubscribe(eventName, callback);
      this.toCallbacks.set(eventName,  [...callbacks, callback]);
      return () => this.unsubscribe(eventName, callback)}  // callable to unsubscribe for convenience

    unsubscribe(eventName, callback){
      let callbacks = this.toCallbacks.get(eventName) || [];
      callbacks = callbacks.filter(subscribedCallback => subscribedCallback !== callback);
      if (callbacks.length > 0) {
        this.toCallbacks.set(eventName, callbacks)}
      else {
        this.toCallbacks.delete(eventName)}
      return callbacks}

    emit(eventName, ...args){
      this.callingBack.set(eventName, this.toCallbacks.get(eventName) || []);
      if (!this.processing.has(eventName)){
        process(this, eventName, args)}}}})();

我喜欢这种方法,因为它很好地分离了关注点,并保持了真正的私密性。唯一的缺点是需要使用'self'(或类似的东西)在私有内容中引用'this'。

你可以试试这个https://www.npmjs.com/package/private-members

这个包将按实例保存成员。

const pvt = require('private-members');
const _ = pvt();

let Exemplo = (function () {    
    function Exemplo() {
        _(this).msg = "Minha Mensagem";
    }

    _().mensagem = function() {
        return _(this).msg;
    }

    Exemplo.prototype.showMsg = function () {
        let msg = _(this).mensagem();
        console.log(msg);
    };

    return Exemplo;
})();

module.exports = Exemplo;

就我个人而言,我喜欢绑定操作符::的建议,然后将其与@d13提到的解决方案结合起来,但现在坚持使用@d13的答案,在这里您为类使用export关键字,并将私有函数放在模块中。

还有一个棘手的解决方案,这里没有提到,下面是更实用的方法,将允许它在类中拥有所有的私有道具/方法。

Private.js

export const get = state => key => state[key];
export const set = state => (key,value) => { state[key] = value; }

. js

import { get, set } from './utils/Private'
export default class Test {
  constructor(initialState = {}) {
    const _set = this.set = set(initialState);
    const _get = this.get = get(initialState);

    this.set('privateMethod', () => _get('propValue'));
  }

  showProp() {
    return this.get('privateMethod')();
  }
}

let one = new Test({ propValue: 5});
let two = new Test({ propValue: 8});
two.showProp(); // 8
one.showProp(); // 5

请对此提出意见。