当在具有ownKeys处理程序的代理对象上调用Object.keys()和Object.getOwnPropertyNames()时,为什么会产生不同的输出?

19

我有以下代理:

const p = new Proxy({}, {
  ownKeys(target) {
    return ['a', 'b'];
  },
});

MDN表示:

这个陷阱可以拦截以下操作:

  • Object.getOwnPropertyNames()
  • Object.getOwnPropertySymbols()
  • Object.keys()
  • Reflect.ownKeys()

因此,我预期Object.getOwnPropertyNames()Object.keys()会产生相同的输出。然而,Object.getOwnPropertyNames(p)返回['a','b'](如预期),但Object.keys(p)返回一个空数组。为什么会这样?

此外,如果我向该对象添加一个未被ownKeys处理程序返回的属性(例如c),则两个函数都会忽略它(它们不会更改其输出)。然而,当我添加一个由ownKeys处理程序返回的属性(例如a)时,Object.keys(p)现在将返回['a']
代码片段:

const p = new Proxy({}, {
  ownKeys(target) {
    return ['a', 'b'];
  },
});

console.log(Object.getOwnPropertyNames(p)); // ['a', 'b']
console.log(Object.keys(p)); // []

p.c = true;
console.log(Object.getOwnPropertyNames(p)); // ['a', 'b']
console.log(Object.keys(p)); // []

p.a = true;
console.log(Object.getOwnPropertyNames(p)); // ['a', 'b']
console.log(Object.keys(p)); // ['a']

2个回答

29
Object.keys()Object.getOwnPropertyNames()的区别在于,Object.keys()会在对象上调用[[GetOwnProperty]]方法,只有返回的属性描述符为可枚举时,才将该属性添加到结果列表中。由于对象没有这样的属性,[[GetOwnProperty]]将返回undefined,因此该属性(名称)被忽略。
您可以通过实现getOwnPropertyDescriptor来覆盖/实现代理中的[[GetOwnProperty]]

const p = new Proxy({}, {
  ownKeys(target) {
    return ['a', 'b'];
  },
  getOwnPropertyDescriptor(k) {
    return {
      enumerable: true,
      configurable: true,
    };
  }
});

console.log(Object.getOwnPropertyNames(p)); // ['a', 'b']
console.log(Object.keys(p)); // ['a', 'b']


javascript 中,答案的值只由处理程序返回,而不是在 target 对象中设置,对吗? - guest271314
目标对象{}没有设置任何实际属性; 虽然{}没有在Proxy()调用外部分配标识符,但可以使用函数参数引用目标对象。该数组或对象仅由函数return返回,而不是在目标{}处进行设置? - guest271314
@FelixKling 所以,按照你的思路,如果使用Object.defineProperty定义a和b并将其设置为可枚举,那么应该能够列出它们,对吗?我尝试了一下,但没有成功。你有什么想法为什么会这样吗? - David Sarmiento

16
Object.keysObject.getOwnPropertyNames的区别在于后者返回自身属性,无论它们是否可枚举。

Proxy添加到对象中的属性是不可枚举的,因此不会显示在Object.keys中,但会显示在Object.getOwnPropertyNames

通常,通过赋值或属性初始化程序添加的属性默认情况下是可枚举的,而使用诸如Object.assignnew Proxy等方法添加的属性默认情况下是不可枚举的。

有关属性所有权和可枚举性的更多信息,请参见MDN,在那里还可以找到概述两种方法差异的表格

enter image description here


4
我不知道那张桌子,太好了! - Felix Kling

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