如何将javascript对象属性设为私有,以便Object.keys()
和Object.getOwnPropertyNames()
不返回该属性?
答案 0 :(得分:3)
如何将JavaScript对象属性设为私有,以便
Object.keys()
和Object.getOwnPropertyNames()
不返回该属性?
您使用的是“私人”一词,然后您描述的行为与该词通常所指的行为不同。
“私有”通常表示无法从对象外部访问属性或值。 Object.keys()
未报告的内容被称为enumerable。
defineProperty
定义的任何属性默认情况下都不可枚举,所以
Object.defineProperty(obj, 'privateField', {value: 5});
或,明确指定为
Object.defineProperty(obj, 'privateField', {value: 5, enumerable: false});
会导致obj.privateField
无法枚举,因此不会包含在Object.keys()
的结果中。
如果你真的希望一个属性在通常意义上是私有的 - 意味着它不能从对象的外部方法访问 - 那么一些选项包括:
使用TypeScript及其private
关键字。这将导致尝试外部访问引发编译时错误。
等待private fields的JS增强功能,其格式可能为#foo
。
在闭包内使用变量来表示私有值。
使用符号作为属性名称,但这可能无法确保真正的隐私。
使用WeakMap
代表私人财产,如另一个答案所示。
根据评论中的建议将您的对象包裹在Proxy
中,该评论会阻止对私有财产的访问。
有关详情和想法,请参阅this question。
答案 1 :(得分:2)
这是使用闭包和WeakMap实现私有属性的类的演示:
const Private = function () {
const weakPrivateScope = new WeakMap()
return class Private {
constructor() {
weakPrivateScope.set(this, {})
}
get(propertyName) {
return weakPrivateScope.get(this)[propertyName]
}
set(propertyName, value) {
return weakPrivateScope.get(this)[propertyName] = value
}
has(propertyName) {
return Object.keys(weakPrivateScope.get(this)).includes(propertyName)
}
delete(propertyName) {
return delete weakPrivateScope.get(this)[propertyName]
}
}
}()
class MyClass extends Private {
constructor() {
super()
this.myPrivateProperty = 'initial value'
}
get myPrivateProperty() {
return this.get('myPrivateProperty')
}
set myPrivateProperty(value) {
return this.set('myPrivateProperty', value)
}
}
let myObject = new MyClass()
console.log('able to access and update value normally:')
console.log('myObject.myPrivateProperty')
console.log(myObject.myPrivateProperty)
console.log('myObject.myPrivateProperty = "new value"')
myObject.myPrivateProperty = 'new value'
console.log(myObject.myPrivateProperty)
console.log('keys() and getOwnPropertyNames() do not get the property:')
console.log(Object.keys(myObject))
console.log(Object.getOwnPropertyNames(myObject))
console.log('you can check for existence and delete the property as well:')
console.log('myObject.has("myPrivateProperty")')
console.log(myObject.has('myPrivateProperty'))
console.log('myObject.delete("myPrivateProperty")')
myObject.delete('myPrivateProperty')
console.log(myObject.has('myPrivateProperty'))