【问题标题】:Why does Object.keys() and Object.getOwnPropertyNames() produce different output when called on a Proxy object with ownKeys handler?为什么 Object.keys() 和 Object.getOwnPropertyNames() 在使用 ownKeys 处理程序在代理对象上调用时会产生不同的输出?
【发布时间】:2016-11-01 00:43:18
【问题描述】:

我有以下代理:

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

代码sn-p:

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

【问题讨论】:

    标签: javascript ecmascript-6 es6-proxy


    【解决方案1】:

    Object.keys()Object.getOwnPropertyNames()的区别在于Object.keys() will invoke [[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 的 Answer 值仅由处理程序返回,而不是在 target 对象中设置,是吗?
    • target 对象{} 处似乎没有设置实际属性;尽管{}Proxy() 调用之外没有标识符,但可以使用函数的参数来引用目标对象。数组或对象仅由函数returned,未设置在target{}?
    • @FelixKling 因此,按照您的思路,如果使用 Object.defneProperty 定义 a 和 b 并将其设置为可枚举,则应该能够列出它们,对吗?我试过了,但没有用。知道为什么吗?
    【解决方案2】:

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

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

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

    MDN 上还有更多关于财产所有权和可枚举性的信息,您还可以在其中找到概述这两种方法差异的表格

    【讨论】:

    • 我不知道那张桌子,这很棒!
    猜你喜欢
    • 2021-03-28
    • 1970-01-01
    • 2017-03-17
    • 1970-01-01
    • 2016-12-28
    • 2018-06-19
    • 2014-03-24
    • 2019-04-14
    • 1970-01-01
    相关资源
    最近更新 更多