是否可以在ES6类中创建私有属性?
举个例子。 如何阻止访问instance.property?
class Something {
constructor(){
this.property = "test";
}
}
var instance = new Something();
console.log(instance.property); //=> "test"
是否可以在ES6类中创建私有属性?
举个例子。 如何阻止访问instance.property?
class Something {
constructor(){
this.property = "test";
}
}
var instance = new Something();
console.log(instance.property); //=> "test"
当前回答
你可以试试这个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;
其他回答
这取决于你问谁:-)
最大最小类提案中没有包含私有属性修饰符,这似乎已经进入了当前的草案。
但是,可能会支持私有名称,它允许私有属性—而且它们可能也可以用于类定义中。
我用这个模式,它总是对我有效
class Test { constructor(data) { class Public { constructor(prv) { // public function (must be in constructor on order to access "prv" variable) connectToDb(ip) { prv._db(ip, prv._err); } } // public function w/o access to "prv" variable log() { console.log("I'm logging"); } } // private variables this._data = data; this._err = function(ip) { console.log("could not connect to "+ip); } } // private function _db(ip, err) { if(!!ip) { console.log("connected to "+ip+", sending data '"+this.data+"'"); return true; } else err(ip); } } var test = new Test(10), ip = "185.167.210.49"; test.connectToDb(ip); // true test.log(); // I'm logging test._err(ip); // undefined test._db(ip, function() { console.log("You have got hacked!"); }); // undefined
我认为Benjamin的答案在大多数情况下可能是最好的,直到语言本身支持显式私有变量。
但是,如果出于某种原因需要阻止使用object . getownpropertysymbols()进行访问,我考虑使用的一种方法是附加一个惟一的、不可配置的、不可枚举的、不可写的属性,可以将其用作构造中的每个对象的属性标识符(例如惟一的Symbol,如果您还没有其他一些惟一的属性,如id)。然后使用该标识符保存每个对象的“私有”变量的映射。
const privateVars = {};
class Something {
constructor(){
Object.defineProperty(this, '_sym', {
configurable: false,
enumerable: false,
writable: false,
value: Symbol()
});
var myPrivateVars = {
privateProperty: "I'm hidden"
};
privateVars[this._sym] = myPrivateVars;
this.property = "I'm public";
}
getPrivateProperty() {
return privateVars[this._sym].privateProperty;
}
// A clean up method of some kind is necessary since the
// variables won't be cleaned up from memory automatically
// when the object is garbage collected
destroy() {
delete privateVars[this._sym];
}
}
var instance = new Something();
console.log(instance.property); //=> "I'm public"
console.log(instance.privateProperty); //=> undefined
console.log(instance.getPrivateProperty()); //=> "I'm hidden"
与使用WeakMap相比,这种方法的潜在优势是,如果需要考虑性能,则访问时间更快。
我有一个解决办法,它很简单…虽然性能不是问题…但它确实有效,而且效果很好。
诀窍在于,在私有属性和函数被建立和标准化/采用之前,需要另一种解决方案,这是另一种解决方案…
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'));
就像我提到的,这个问题不是最好的,但它工作,使属性真正的私有。
在寻找“类的私有数据”的最佳实践时,我偶然看到了这篇文章。上面提到了一些模式会有性能问题。
我根据在线书籍“探索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();