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

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

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

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

当前回答

就我个人而言,我喜欢绑定操作符::的建议,然后将其与@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

请对此提出意见。

其他回答

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,但在示例中它看起来更简洁。

根据ES2022,我们可以在JavaScript类中添加私有属性和方法。

我们可以通过在私有字段的名称前预先挂起#来定义它们。

演示:

类Something { #property = "test";//通过在属性名后面加上#,我们使它成为私有的。 } var instance = new Something(); console.log(实例。#产权);私有字段'#property'必须在一个外围类中声明

在寻找“类的私有数据”的最佳实践时,我偶然看到了这篇文章。上面提到了一些模式会有性能问题。

我根据在线书籍“探索ES6”中的4个主要模式整理了一些jsperf测试:

http://exploringjs.com/es6/ch_classes.html#sec_private-data-for-classes

测试可以在这里找到:

https://jsperf.com/private-data-for-classes

在Chrome 63.0.3239 / Mac OS X 10.11.6中,表现最好的模式是“通过构造函数环境的私有数据”和“通过命名约定的私有数据”。对我来说,Safari在WeakMap上表现得很好,而Chrome则不太好。

我不知道对内存的影响,但“构造函数环境”的模式(有些人曾警告过这将是一个性能问题)非常具有性能。

这4种基本模式是:

通过构造函数环境的私有数据

class Countdown {
    constructor(counter, action) {
        Object.assign(this, {
            dec() {
                if (counter < 1) return;
                counter--;
                if (counter === 0) {
                    action();
                }
            }
        });
    }
}
const c = new Countdown(2, () => {});
c.dec();
c.dec();

通过构造函数环境的私有数据2

class Countdown {
    constructor(counter, action) {
        this.dec = function dec() {
            if (counter < 1) return;
            counter--;
            if (counter === 0) {
                action();
            }
        }
    }
}
const c = new Countdown(2, () => {});
c.dec();
c.dec();

通过命名约定的私有数据

class Countdown {
    constructor(counter, action) {
        this._counter = counter;
        this._action = action;
    }
    dec() {
        if (this._counter < 1) return;
        this._counter--;
        if (this._counter === 0) {
            this._action();
        }
    }
}
const c = new Countdown(2, () => {});
c.dec();
c.dec();

通过WeakMaps的私有数据

const _counter = new WeakMap();
const _action = new WeakMap();
class Countdown {
    constructor(counter, action) {
        _counter.set(this, counter);
        _action.set(this, action);
    }
    dec() {
        let counter = _counter.get(this);
        if (counter < 1) return;
        counter--;
        _counter.set(this, counter);
        if (counter === 0) {
            _action.get(this)();
        }
    }
}
const c = new Countdown(2, () => {});
c.dec();
c.dec();

通过符号的私有数据

const _counter = Symbol('counter');
const _action = Symbol('action');

class Countdown {
    constructor(counter, action) {
        this[_counter] = counter;
        this[_action] = action;
    }
    dec() {
        if (this[_counter] < 1) return;
        this[_counter]--;
        if (this[_counter] === 0) {
            this[_action]();
        }
    }
}
const c = new Countdown(2, () => {});
c.dec();
c.dec();

使用WeakMap可以在类中拥有私有方法。

根据MDN网络文档:

WeakMap对象是键/值对的集合,其中键仅为对象,值可以是任意值。 键中的对象引用是弱保存的,这意味着如果不再有对该对象的其他引用,则它们是垃圾收集(GC)的目标。

这是一个创建带有私有成员_items的Queue数据结构的例子,该成员_items包含一个数组。

const _items = new WeakMap();

class Queue {    
    constructor() {
        _items.set(this, []);
    }

    enqueue( item) {
        _items.get(this).push(item);
    }    

    get count() {
        return _items.get(this).length;        
    }

    peek() {
        const anArray = _items.get(this);
        if( anArray.length == 0)
            throw new Error('There are no items in array!');

        if( anArray.length > 0)
            return anArray[0];
    }

    dequeue() {        
        const anArray = _items.get(this);
        if( anArray.length == 0)
            throw new Error('There are no items in array!');

        if( anArray.length > 0)
            return anArray.splice(0, 1)[0];
    }    
}

使用的例子:

const c = new Queue();
c.enqueue("one");
c.enqueue("two");
c.enqueue("three");
c.enqueue("four");
c.enqueue("five");
console.log(c);

私有成员_items是隐藏的,不能在Queue对象的属性或方法中看到:

然而,Queue对象中的私有成员_items可以通过以下方式访问:

const anArray = _items.get(this);

这取决于你问谁:-)

最大最小类提案中没有包含私有属性修饰符,这似乎已经进入了当前的草案。

但是,可能会支持私有名称,它允许私有属性—而且它们可能也可以用于类定义中。