如果可写属性默认为false,JS对象如何是可变的?

4

我正在尝试了解JS中的对象变异是如何工作的。我遇到了JS中的可写属性。

var x = {name:'JohnSnow'};

Object.defineProperty(x, 'name', {
   writable: false
};

现在更改name属性对对象x没有影响。这是可以理解的,因为我已将其writable属性更改为false

然而,我阅读过的所有文档,包括(https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperties#Parameters)都说此属性默认为false

如果writable默认设置为false,那么对象不应该默认是不可变的,并且只有在将writable设置为true后才能变为可变的。

我是否在理解对象属性的概念方面错了,因为我认为JS中的所有对象都具有此config,并且每个对象都具有writable属性。

1个回答

7

Object.defineProperty通常只用于定义一个新的属性——否则,传递的属性描述符对象往往会被部分忽略,正如9.1.6.3步骤2所述。

在第2步中,如果当前描述符未定义,则仅将新描述符desc作为新属性描述符放置。

在第6步中,现有的数据属性可能会转换为访问器属性(或者反之),但是

保留转换后属性的[[Configurable]]和[[Enumerable]]属性的现有值,并将该属性的其余属性设置为它们的默认值

第7步和第8步不会更改当前描述符,它们只是验证并返回一个值。

因此,无论传递了什么样的描述符,如果该属性已经存在于对象中,则"新"描述符的writable属性(或其缺失)将被完全忽略。


writable 默认为 false,但仅当使用 Object.defineProperty 时。

var x = {};

Object.defineProperty(x, 'name', {
   value: 'foo'
});

x.name = 'bar';
console.log(x.name);

正如您在上面看到的,如果在调用Object.defineProperty时未提供可写属性,则默认为false。这只是意味着它没有指定属性默认为不可写,它仅指定使用Object.defineProperty定义属性时属性为不可写。
当使用对象文字定义对象时,对象属性是可写的,如12.2.6.7 Runtime Semantics: Evaluation ObjectLiteral : {}中所述:
Perform ? PropertyDefinitionEvaluation of PropertyDefinitionList with arguments obj and true.
这最终会导致:
CreateDataProperty ( O, P, V ):
让newDesc成为属性描述符,其值为V,[[Writable]]为true,[[Enumerable]]为true,[[Configurable]]为true。

挑剔一点:当您使用Object.defineProperty修改现有属性,如问题中所示,而不是定义或重新定义一个新属性时,它将不会像writable: false一样起作用。 - Ry-
@CertainPerformance 这意味着只有当你在对象上调用definePropertydefineProperties方法时,整个对象配置概念才会出现在画面中。 - Saurabh Tiwari
@SaurabhTiwari: 并非如此。尝试使用Object.getOwnPropertyDescriptor(x, 'name')而没有任何defineProperties。默认值取决于情况。例如,当您在对象字面量中使用普通属性或使用= 分配新属性时,该属性是可写的和枚举的。但是如果您使用class定义了一个类,则来自其中方法的原型上的属性是可写的但*不可枚举的。 - Ry-

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接