在JavaScript中更改元数据是如何工作的?
在控制台中,abc尽管设置了{writable:false}. 你能解释一下改变元数据是如何工作的吗?
let portfolio = {
myFirstName: "Bob",
myLastName: "Alice",
myAge: 26,
aboutMe: function() {
return ("First Name: " + this.myFirstName + "; Last Name: " + this.myLastName + "; Age: " + this.myAge + ";");
}
};
Object.defineProperty(portfolio, "myFirstName", { writable: false });
Object.defineProperty(portfolio, "myFirstName", { value: "abc" });
console.log(portfolio.myFirstName);
回答
在您的第二行中,Object.defineProperty(portfolio, "myFirstName", { value: "abc" });您再次定义了该属性。
您没有分配值。您正在扔掉旧房产并用全新的品牌取而代之。(技术上不正确,它经历了很多步骤来评估和应用值到属性属性,但为了简单理解,我相信这足以理解,因为在这种情况下感觉就像一个新的。如果你愿意,请阅读链接拥有复杂的真相)
要分配新值使用portfolio.myFirstName = "value here",您会看到它被写保护。
let portfolio = {
myFirstName: "Bob",
myLastName: "Alice",
myAge: 26,
aboutMe: function() {
return ("First Name: " + this.myFirstName + "; Last Name: " + this.myLastName + "; Age: " + this.myAge + ";");
}
};
Object.defineProperty(portfolio, "myFirstName", { writable: false });
portfolio.myFirstName = "Alice";
console.log(portfolio.myFirstName);
为防止变通方法,请Object.freeze()在修改其属性后调用该对象。这也会产生其他副作用,例如无法编辑其他属性的值。
let portfolio = {
myFirstName: "Bob",
myLastName: "Alice",
myAge: 26,
aboutMe: function() {
return ("First Name: " + this.myFirstName + "; Last Name: " + this.myLastName + "; Age: " + this.myAge + ";");
}
};
Object.defineProperty(portfolio, "myFirstName", { writable: false });
Object.freeze(portfolio);
Object.defineProperty(portfolio, "myFirstName", {value:"abc"});
console.log(portfolio.myFirstName);
回答
writable: false仅对Object.definePropertyifconfigurable也设置为有影响false。参见ValidateAndApplyPropertyDescriptor算法的第 7 步:
Else if IsDataDescriptor(current) and IsDataDescriptor(Desc) are both true, then
If current.[[Configurable]] is false and current.[[Writable]] is false, then
If Desc.[[Writable]] is present and Desc.[[Writable]] is true, return false.
If Desc.[[Value]] is present and SameValue(Desc.[[Value]], current.[[Value]]) is false, return false.
Return true.
Else if IsDataDescriptor(current) and IsDataDescriptor(Desc) are both true, then
If current.[[Configurable]] is false and current.[[Writable]] is false, then
If Desc.[[Writable]] is present and Desc.[[Writable]] is true, return false.
If Desc.[[Value]] is present and SameValue(Desc.[[Value]], current.[[Value]]) is false, return false.
Return true.
这可能是因为只要属性是可配置的,就没有什么可以阻止您将writableback的值更改为true,例如
Object.defineProperty(
portfolio,
"myFirstName",
{value: "abc", writable: true}
);
请注意,声明为对象文字的一部分的任何属性都会自动具有{writable: true, configurable: true, enumerable: true}.
例子
无法分配,因为writable和configurable都是false:
可以赋值,因为writable或configurable是true:
Object.defineProperty(
portfolio,
"myFirstName",
{value: "abc", writable: true}
);
最后,如果writable和configurable都是false但如果新值与当前值相同,则不会抛出错误,因为实际上没有对属性进行任何更改:
var obj = {};
Object.defineProperty(obj, 'test', {
value: 42,
configurable: false,
writable: false,
enumerable: true,
});
console.log(obj);
Object.defineProperty(obj, 'test', {value: 21});
console.log(obj);
writable: false对于正常赋值 ( foo.bar = 42),设置将按预期工作,因为此类赋值首先会OrdinarySetWithOwnDescriptor检查writable现有属性描述符的值。