[英]Object.keys returns private properties
我有使用 Typescript 創建的類/視圖模型。 我將此類中的一個字段設為私有,以便在我嘗試獲取所有其他類屬性時跳過它。
對嗎,我怎么能跳過我的私人財產?
Object.keys(myObject).forEach(property => {
//some stuff
}
});
我的班級示例:
class MyModel{
id: any = ko.observable('');
name: any = ko.observable('');
address: any = ko.observable('');
city: any = ko.observable('');
state: any = ko.observable('');
country: any = ko.observable('');
private secretField= ko.observable('');
}
TypeScript 編譯私有屬性就像常規屬性一樣,私有屬性的執行僅在編譯時完成,並且它們在運行時仍然存在。
github 上有很多要求即使在運行時也無法訪問私有屬性,但由於設計限制和/或哲學問題,這尚未實現,而且可能永遠不會實現。
您可以在此處閱讀一些設計討論歷史。
這意味着您必須使用自己的約定來處理此問題,例如在名稱前加上下划線並在循環中過濾該名稱。
private
關鍵字僅影響 TypeScript 中的可見性,不影響 JS 輸出。
對於未在原型上定義的類屬性,因此無法使用類屬性裝飾器進行修改,最直接的方法是對私有屬性使用_
命名約定:
class MyModel {
// ...
private _secretField = ko.observable('');
}
Object.keys(myObject)
.filter(key => !(typeof key === 'string' && key.charAt(0) === '_'))
.forEach(property => {
// some stuff
});
你可以從 ES6 開始使用 Symbols。 它可以存儲值並且不會出現在 Object.keys 結果中
JS代碼
const privateStuff = Symbol()
var obj = {
name: "Andrew",
age: 23,
[privateStuff]: "Don't show it"
}
var keys = Object.keys(obj);
keys.forEach((k)=>{console.log(k)});
//get value
var serverStuff=obj[privateStuff]
TL;DR:使用私有標識符來定義您的私有字段。 這樣,它們的可訪問性也將在運行時強制執行。
正如已經指出的那樣,可訪問性僅由 TypeScript 轉譯器靜態地(在編譯時)強制執行。
因此,所有屬性,無論是公共的還是私有的,都作為普通的 JavaScript 屬性發出。 這里沒有魔法,除了使用Proxy
來捕獲ownKeys()
方法或使用Object.defineProperties
而不是以 TypeScript 方式聲明它們之外,您無法做任何事情來隱藏它們。 對於后一個想法,我想出了一個例子:
class Foo {
constructor() {
Object.defineProperties(this, {
bar: {
enumerable: false,
value: "Hello world"
}
})
console.log((this as any).bar)
}
}
上面的例子可以在TypeScript Playground 中測試。
然而,我認為做這樣的事情是一種反模式,因為它破壞了所有的 TypeScript 安全性,這是選擇它而不是僅僅寫出 JavaScript 代碼的唯一原因。
因此,我們剩下的唯一解決方案是使用私有標識符。 這是一個 TypeScript 功能,因此名稱以#
開頭的任何字段不僅在編譯時而且在運行時都被強制為私有。
class Foo {
#bar = "Hello world"
constructor() {
console.log(this.#bar)
}
}
console.log(Object.keys(new Foo()))
上面的例子可以在TypeScript Playground 中測試。
這是如何工作的? 好吧,您可能只是看看轉換后的 JavaScript 代碼,您會突然注意到一個WeakMap
。 實際上,對具有私有標識符的類中的每個字段都定義了對新WeakMap
的引用,在定義它們的聲明類的同一詞法范圍內。 無論在何處訪問私有字段,都是通過調用 getter 或 setter 函數來完成的,該函數使用給定的映射(在引用該字段時傳遞)來獲取或設置給定鍵的值,該鍵是訪問該字段的類的實例上。 在 getter 和 setter 函數中也會進行運行時檢查,以便在使用未注冊的接收器調用時TypeError
,以防止使用不同類型的實例或根本沒有實例訪問私有字段。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.