2016-12-01 80 views
1

我想使用代理創建動態的不可配置屬性。我嘗試這樣做:使用代理創建動態的不可配置屬性

const proxy = new Proxy({}, { 
 
    getOwnPropertyDescriptor() { 
 
    return { 
 
     configurable: false, 
 
     enumerable: false, 
 
    }; 
 
    }, 
 
}); 
 

 
console.log(Reflect.getOwnPropertyDescriptor(proxy, 'test'));

但我發現了一個錯誤:

TypeError: 'getOwnPropertyDescriptor' on proxy: trap reported non-configurability for property 'test' which is either non-existant or configurable in the proxy target

MDN說:

A property cannot be reported as non-configurable, if it does not exists as an own property of the target object or if it exists as a configurable own property of the target object.

但它並不能說明什麼這背後的推理。

有沒有解決此錯誤的方法?

回答

7

不是。這是由於所希望的不變性,即如果您在對象中觀察到不可配置的屬性,它不會神奇地消失。如果它也是不可寫的,它的價值不能改變。

如果你不能依靠這個,getOwnPropertyDescriptor基本上是無用的。

強制您不要使用不可配置的屬性,或者在目標中定義它們,這意味着您不會違反此不變量,因爲不變量通過構造持有目標。也就是說,ECMAScript不允許您以打破這些不變式的方式使用代理自定義設置。

Some of the internal method invariants defined in 6.1.7.3 are essential integrity invariants. These invariants are explicitly enforced by the proxy object internal methods specified in this section. An ECMAScript implementation must be robust in the presence of all possible invariant violations.

因此,要麼將屬性報告爲可配置的,要麼在目標中定義不可配置的屬性。

如果你想要動態屬性,我建議只是說謊的屬性是可配置的。然後添加一個defineProperty陷阱,它返回false,有效地防止重新定義。

+0

很好的解釋,謝謝。你如何看待我的解決方案(發佈爲自己的答案)?是否有任何我沒有想到的副作用? –

+0

@Gothdo是的,這應該正常工作。你可能會遇到像另一個代理或不可擴展對象那樣的更一般的目標,但如果你使用'{}'而不把它暴露給其他代碼,我沒有看到任何問題。 – Oriol

0

看來,如果在getOwnPropertyDescriptor陷阱裏面,我在返回描述符之前在目標對象上定義該屬性,它工作正常。

const proxy = new Proxy({}, { 
 
    getOwnPropertyDescriptor(target, property) { 
 
    const descriptor = { 
 
     configurable: false, 
 
     enumerable: false, 
 
    }; 
 
    Reflect.defineProperty(target, property, descriptor); 
 
    return descriptor; 
 
    }, 
 
}); 
 

 
console.log(Reflect.getOwnPropertyDescriptor(proxy, 'test'));

副作用是(顯然)已創建的屬性,不能被刪除(因爲它是不可配置的),這意味着,例如我以後不能報告爲不存在的,但在我的情況下,這並不重要。