是否可以在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"
当前回答
更新:看别人的回答,这个已经过时了。
简单的回答,不,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; }
}
其他回答
我已经开发了一个模块,帮助您使用的访问限制 JavaScript类,叫做Capsulable。(私有和受保护的静态)
如果您感兴趣,请查看下面的软件包。 https://github.com/hmmhmmhm/capsulable
const Capsulable = require('capsulable')
const Field = Capsulable()
class A {
constructor(_field){
// Configure data fields.
Field(this, _field)
// The code below provides access to
// the data fields when creating
// functions within the class.
Field(this).private
Field(this).protected
Field(this).protectedStatic
}
}
module.exports = A
我用这个模式,它总是对我有效
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
实际上这是可能的。 1. 首先,创建类,并在构造函数中返回被调用的_public函数。 2. 在被调用的_public函数中传递this引用(以获得对所有私有方法和道具的访问),以及构造函数的所有参数(将在new Names()中传递) 3.在_public函数作用域中,还有一个Names类,它可以访问私有Names类的this (_this)引用
class Names {
constructor() {
this.privateProperty = 'John';
return _public(this, arguments);
}
privateMethod() { }
}
const names = new Names(1,2,3);
console.log(names.somePublicMethod); //[Function]
console.log(names.publicProperty); //'Jasmine'
console.log(names.privateMethod); //undefined
console.log(names.privateProperty); //undefind
function _public(_this, _arguments) {
class Names {
constructor() {
this.publicProperty = 'Jasmine';
_this.privateProperty; //"John";
_this.privateMethod; //[Function]
}
somePublicMethod() {
_this.privateProperty; //"John";
_this.privateMethod; //[Function]
}
}
return new Names(..._arguments);
}
另一种方式类似于上两个帖子
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
除了给出的答案之外,您还可以使用代理来创建“私有属性”,使代理只对公共代码可用。实例只对构造函数、绑定方法和作为接收者的Proxy本身可用。
这比使用符号和弱映射有一些优势。
符号是可枚举的,可以用代理捕获。 当实例被代理为实例时,WeakMaps失败!== new Proxy(instance)
WeakMap失败。
const map = new WeakMap()
const instance = new SomeClass()
map.set(instance, 'foo')
// somewhere along the way in 3rd party code
const proxy = new Proxy(instance, {})
assert(map.set(instance) === map.get(proxy)) // fail
const proxy2 = new Proxy(proxy, {})
// more headache
使用代理用私有道具验证来装饰实例
getProxy = (instance) => new Proxy(instance, {
get: (target, name, receiver) => {
console.log('get', { target, name, receiver })
if (name[0] === '_') throw new Error('Cannot access private property ' + name)
return Reflect.get(target, name, receiver)
},
set: (target, name, value, receiver) => {
console.log('set', { target, name, value, receiver })
if (name[0] === '_') throw new Error('Cannot set private property ' + name)
return Reflect.set(target, name, value, receiver)
}
})
class PublicClass {
constructor() {
Object.defineProperty(this, '_privateProp', { enumerable: false, writable: true, configurable: false })
return getProxy(this) // can be moved out as a decorator
}
getPrivatePropFail() {
return this._privateProp // fail
}
getPrivateProp = () => {
return this._privateProp // ok
}
setPrivateProp = (value) => {
return this._privateProp = value // ok
}
}
pub = new PublicClass()
try {
console.log('get pub._privateProp', pub._privateProp)
} catch(e) {
console.error(e)
}
try {
console.log('set pub._privateProp', pub._privateProp = 'you fail')
} catch(e) {
console.error(e)
}
pub.setPrivateProp('you ok')
console.log('pub.getPrivateProp()', pub.getPrivateProp())
console.log('pub', Object.keys(pub))
这种方法的优点
私有属性访问验证被装饰在实例上(可选)。 私有属性可以在控制台、调试器和测试环境中检查,属性简单(没有符号或映射) 您可以控制验证和错误处理
的缺点
代理增加了开销和抽象级别 调试将显示包装对象的Proxy() 访问私有道具的方法需要是箭头函数 当无意中暴露实例时,可能会泄漏私有道具。添加一个方法getSelf = () => this
注:
考虑到开销,这种方法可以用于属性封装和调试的清晰度超过开销的场景。例如,当从存储中填充模型时。如。setjson (json)将确保没有私有道具被破坏。
通过使用WeakMap和Proxy来确保“私有”属性不可见,同时允许在每个作用域上使用相同实例访问WeakMap,可以进一步调整此方法以提供更好的封装。然而,这牺牲了可读性和调试。