无法更改数据属性的值。访问器属性(getter和setter)的工作方式相同(并且仍然给出了您正在更改值的错觉)。请注意,仍然可以修改作为对象的值,除非它们也被冻结。作为对象,可以冻结数组,之后不能更改其元素。也不能添加或删除任何元素。
'use strict'
document.body.innerHTML = "Hello#1";
var frozen = Object.freeze(document.body);
document.body = frozen;
console.log("Same frozen body (First):", document.body === frozen)
console.log(document.body['innerHTML']);
// Why I can modify this property?
document.body.innerHTML = "Hello#2";
console.log("Same frozen body (Second):", document.body === frozen);
console.log(document.body['innerHTML']);
此代码段正在使用getter
和setter
(此方法失败)
'use strict'
var myObj = {
a: "Ele#1",
get innerHTML() {
return this.a;
},
set innerHTML(html) {
this.a = html;
}
}
myObj = Object.freeze(myObj);
myObj.innerHTML = "Ele";
console.log(myObj);
为什么在“冻结”身体对象后,我可以修改它的属性?例如,innerHTML
?
我可能缺乏信息,我不知道!
答案 0 :(得分:3)
innerHTML
是一个访问者属性。如果您将document.body
调试到控制台并向下钻取原型链,您可以在Element
中将其定义为get innerHTML()
和set innerHTML()
。
这是一个如何实现同样目标的准系统示例:
var myObj = (function() {
var html = null;
return {
get innerHTML() { return html; },
set innerHTML(value) { html = value; }
};
})();
答案 1 :(得分:2)
访问者属性(getter和setter)的工作方式相同(并且仍然给出了您正在更改值的错觉)。
innerHTML
确实是一个访问者属性,如下所示,in the specification:
function getPropertyDescriptor(object, property) {
while (typeof object === 'object' && object !== null) {
const descriptor = Object.getOwnPropertyDescriptor(object, property)
if (descriptor) {
return descriptor
}
object = Object.getPrototypeOf(object)
}
}
const desc = getPropertyDescriptor(document.body, 'innerHTML')
console.log(desc)

修改简化示例以使用WeakMap
代替属性,您可以使其有效:
'use strict'
const Element = (() => {
const weakPrivate = new WeakMap()
return class Element {
constructor () {
weakPrivate.set(this, { innerHTML: 'initial' })
}
get innerHTML () {
return weakPrivate.get(this).innerHTML
}
set innerHTML (value) {
return weakPrivate.get(this).innerHTML = value
}
}
})()
let object = new Element()
Object.freeze(object)
console.log(object.innerHTML)
object.innerHTML = 'new value'
console.log(object.innerHTML)