2017-07-16 107 views
1

如何使私人的JavaScript對象屬性,以便Object.keys()Object.getOwnPropertyNames()不返回該屬性?有沒有辦法讓私人的JavaScript對象屬性?

+1

通過使用正常的類聲明,我不認爲這是可能的。但是聲明類的[**其他方式**](/ questions/5140833/privateness-in-javascript)。 –

+0

什麼是應用程序?你可以使用'Proxy'。另請參閱https://stackoverflow.com/questions/40386767/how-to-create-static-array-in-javascript/ – guest271314

回答

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()的結果。

如果你真的想要一個特性,在通常意義上的私人 - 這意味着它不能從對象上的方法外訪問 - 然後一些選項包括:

  1. 使用打字稿及private關鍵字。這將導致嘗試的外部訪問引發編譯時錯誤。

  2. 等待JS增強爲private fields,可能採取的格式爲#foo

  3. 在閉包中使用變量來表示私有值。

  4. 使用符號作爲屬性名稱,但這可能不能確保真正的隱私。

  5. 使用WeakMap來表示私有財產,如在另一個答案中所建議的。

  6. 將您的對象包裝在Proxy中,如評論中所建議的那樣,它禁止訪問私有財產。

欲瞭解更多詳情和想法,請參閱this question

+0

代理聽起來像是一個非常糟糕的主意 - 它將如何知道允許或拒絕訪問? – Bergi

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'))

+0

請注意,ECMAScript 5中也可以這樣做,但除非實施了內存泄漏對該類使用'destroy()'方法,並在丟失對該對象實例的引用之前對其進行調用。 –

相關問題