在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}.

例子

无法分配,因为writableconfigurable都是false

可以赋值,因为writableconfigurabletrue

Object.defineProperty(
  portfolio,
  "myFirstName",
  {value: "abc", writable: true}
);

最后,如果writableconfigurable都是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现有属性描述符的值。


以上是在JavaScript中更改元数据是如何工作的?的全部内容。
THE END
分享
二维码
< <上一篇
下一篇>>