JavaScript中Object.defineProperty()的奇怪行为

75

我正在尝试使用以下Javascript代码,涉及到Object.defineProperty()的了解,并且我遇到了一个奇怪的问题。当我在浏览器或VS代码中尝试执行以下代码时,输出结果与预期不符,但是如果我尝试调试代码,则输出结果是正确的。

当我调试代码并评估配置文件时,我可以看到对象中的name和age属性。但在输出时,它只显示name属性。

//Code Snippet 
let profile = {
  name: 'Barry Allen',
}

// I added a new property in the profile object.
Object.defineProperty(profile, 'age', {
  value: 23,
  writable: true
})

console.log(profile)
console.log(profile.age)

现在这里期望的输出应该是

{name: "Barry Allen", age: 23}
23

但是我得到的输出是这样的。 请注意,我能够访问后面定义的age属性。 我不确定为什么console.log()会表现出这种方式。

{name: "Barry Allen"}
23 
3个回答

90

Object.defineProperty 中,enumerable 默认为false,你应该将其设置为 true。根据MDN文档

enumerable

如果且仅当相应对象的属性在枚举时会显现出来则为true

默认为false。

非枚举意味着该属性在 Object.keys() 或者 for..in 循环中以及控制台中都不会被显示。

let profile = {
    name: 'Barry Allen',
}

// I added a new property in the profile object.

Object.defineProperty(profile , 'age', {
    value: 23,
    writable: true,
    enumerable: true
})
console.log(profile)
console.log(profile.age)

内置类的prototype对象上的所有属性和方法均为不可枚举。 这就是您可以从实例调用它们但它们在迭代时不会出现的原因。

要获取所有属性(包括不可枚举),请使用 Object​.get​OwnProperty​Names()

let profile = {
    name: 'Barry Allen',
}

// I added a new property in the profile object.

Object.defineProperty(profile , 'age', {
    value: 23,
    writable: true,
    enumerable: false
})
for(let key in profile) console.log(key) //only name will be displayed.

console.log(Object.getOwnPropertyNames(profile)) //You will se age too


我之前不知道这个,但是当我在浏览器中运行本地代码时,它完美地显示出来了(尽管明确将“enumerable”指定为false)。 - random
1
我没有为age设置enumerable为true,但它仍然被显示出来。 - random
请查看某个性能答案的评论,@randomSoul。 - Maheer Ali
7
在Chrome控制台中,您应该看到未枚举的属性被略微透明地着色。 - yqlim
5
@randomSoul 这是一项调试功能而不是语言功能。如果你改用 JSON.stringify,它将表现一致,并且省略非“可枚举”的属性。 - Mike Caron
显示剩余3条评论

25

默认情况下,使用defineProperty定义的属性是不可枚举的 - 这意味着当您遍历它们的Object.keys时(这就是代码段控制台执行的操作),它们不会显示出来。(同样,数组的length属性也不会被显示,因为它是不可枚举的。)

参见MDN:

enumerable

如果且仅如果此属性在对应对象上的属性枚举中显示,则为true。

默认为false。

将其改为可枚举:

//Code Snippet 
let profile = {
  name: 'Barry Allen',
}

// I added a new property in the profile object.
Object.defineProperty(profile, 'age', {
  value: 23,
  writable: true,
  enumerable: true
})

console.log(profile)
console.log(profile.age)

你看到 记录的图像 里的属性是因为 Chrome 控制台会展示不可枚举属性,但这些不可枚举属性会略微变灰: enter image description here 注意到 age 是灰色的,而 name 不是 - 这表明 name 是可枚举的,而 age 不是。

有人给了这个 https://pasteboard.co/IaOxMqB.png 在Chrome控制台中显示age属性。你能解释一下吗?Chrome控制台的工作方式不同吗? - Maheer Ali
3
没问题,这是Chrome控制台的行为 - 它会显示所有属性,包括不可枚举的属性,请参见编辑。不可枚举的属性(如age__proto__)将略微变灰。 - CertainPerformance

5
无论何时使用对象的".defineProperty"方法时,最好定义描述符的所有属性。因为如果您不定义其他属性描述符,则它会为所有属性假定默认值,即false。因此,您的console.log检查所有可枚举:true属性并记录它们。
//Code Snippet 
let profile = {
  name: 'Barry Allen',
}

// I added a new property in the profile object.
Object.defineProperty(profile, 'age', {
  value: 23,
  writable: true,
  enumerable : true,
  configurable : true
})

console.log(profile)
console.log(profile.age)

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