17

我有以下代理:

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']

4

2 回答 2

26

Object.keys()和之间的区别在于Object.getOwnPropertyNames()Object.keys()它将在对象上调用,并且仅当返回的属性描述符为[[GetOwnProperty]]enumerable时才将该属性添加到结果列表中。由于对象没有这样的属性,[[GetOwnProperty]]将返回undefined并且属性(名称)被忽略。

[[GetOwnProperty]]您可以通过实现在代理中覆盖/实现getOwnPropertyDescriptor

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']

于 2016-11-01T00:55:23.953 回答
16

Object.keys和之间的区别在于Object.getOwnPropertyNames后者返回自己的属性,而不管它们是否可枚举。

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

一般情况下,通过赋值或属性初始化器添加的属性默认是可枚举的,通过 等方法添加的属性默认Object.assignnew Proxy不可枚举的。

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

在此处输入图像描述

于 2016-11-01T00:51:13.887 回答