有没有办法使 javascript 对象 属性 私有化?

Is there a way to make private a javascript object property?

如何将 javascript 对象设为私有 属性,以便 Object.keys()Object.getOwnPropertyNames() 不会 return 那个 属性?

这是一个 class 使用闭包和 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'))

How can I make private a JavaScript object property so that Object.keys() and Object.getOwnPropertyNames() don't return that property?

您使用的是术语 "private",然后您描述的行为与该词通常所指的行为不同。

"Private" 通常表示 属性 或值无法从对象外部访问。未被 Object.keys() 报告被称为不是 enumerable

defineProperty定义的任何属性在默认情况下都是不可枚举的,所以

Object.defineProperty(obj, 'privateField', {value: 5});

或者,如

中那样明确指定
Object.defineProperty(obj, 'privateField', {value: 5, enumerable: false});

将导致 obj.privateField 不可枚举,因此不包含在 Object.keys() 的结果中。

如果您真的希望 属性 在通常意义上是私有的——这意味着它不能从对象的外部方法访问——那么一些选项包括:

  1. 使用 TypeScript 及其 private 关键字。这将导致尝试的外部访问引发编译时错误。

  2. 等待 private fields 的 JS 增强功能,可能采用 #foo.

  3. 的形式
  4. 在闭包中使用变量来表示私有值。

  5. 为 属性 名称使用符号,尽管这可能无法确保真正的隐私。

  6. 使用 WeakMap 表示私有 属性,如另一个答案中所建议。

  7. 按照评论中的建议将您的对象包裹在 Proxy 中,这会阻止对私有 属性.

  8. 的访问

有关更多详细信息和想法,请参阅 this question