为什么 Object.keys() 和 Object.getOwnPropertyNames() 在使用 ownKeys 处理程序调用 Proxy 对象时会产生不同的输出?

Why does Object.keys() and Object.getOwnPropertyNames() produce different output when called on a Proxy object with ownKeys handler?

我有以下代理:

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

MDN 表示:

This trap can intercept these operations:

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

因此,我希望 Object.getOwnPropertyNames()Object.keys() 产生相同的输出。但是,Object.getOwnPropertyNames(p) returns ['a', 'b'](如预期),但 Object.keys(p) returns 是一个空数组。这是为什么?

此外,如果我向该对象添加一个 属性 而不是由 ownKeys 处理程序返回(例如 c),它会被两个函数忽略(它们不'改变他们的输出)。但是,当我添加由 ownKeys 处理程序(例如 a)返回的 属性 时,现在 Object.keys(p) returns ['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']

Object.keysObject.getOwnPropertyNames的区别在于后者returns拥有属性,不管它们是否可枚举。

Proxy添加到对象的属性是不可枚举的,不会出现在Object.keys中,但会出现在Object.getOwnPropertyNames

通常,通过赋值或属性初始化器添加的属性默认是可枚举的,而通过Object.assignnew Proxy等方法添加的属性默认是不可枚举的.

MDN 上有更多关于 属性 所有权和可枚举性的内容,您还可以在其中找到这个 table,它概述了两种方法的区别

对象上Object.keys() and Object.getOwnPropertyNames() is that Object.keys() will invoke [[GetOwnProperty]]的区别,如果returned 属性描述符为,则只将属性添加到结果列表可枚举。由于对象没有这样的 属性,[[GetOwnProperty]] 将 return undefined 并且忽略 属性(名称)。

您可以通过实施 getOwnPropertyDescriptor:

在代理中 overwrite/implement [[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']