【问题标题】:Accessing a object's non enumerable properties访问对象的不可枚举属性
【发布时间】:2018-12-18 10:28:53
【问题描述】:

下面这个问题:Object.prototype returns empty object in Node问了

为什么console.log(Object.prototype) 不记录预期的对象,而是返回{}

答案如下:

这是因为console.log [...] 在对象上使用了Object.keys(),并且它只返回可枚举的属性。而Object.prototype 包含不可枚举的属性,这就是它返回空节点的原因。

-Amrender Singh


我想知道如何输出给定对象的所有属性(例如Object.prototype)。如另一个答案所示,使用getOwnPropertyNames 工作正常:

const ObjectPrototype = Object.getOwnPropertyNames(Object.prototype).reduce((object, name) => {

  object[name] = Object.prototype[name];

  return object;

}, {});

console.log(
  ObjectPrototype
);
.as-console-wrapper { max-height: 100% !important; top: 0; }

我认为我可以通过这种方式提取给定对象的 隐藏 属性。但实际上,它并没有完全起作用。

这是一个更简单的示例:我正在检查的对象是对象{mykey: 'value'}。 Chrome 给了我它的属性(console.log 也给了我)还有它的原型,__proto__ 变灰了:

let object = { mykey: 'value' };

object = Object.getOwnPropertyNames(object).reduce((acc, name) => {

  acc[name] = object[name];

  return acc;

}, {});

console.log(
  object
);
.as-console-wrapper { max-height: 100% !important; top: 0; }

上面只返回一个属性。我期待也有__proto__有没有办法显示一个人的所有属性,包括 隐藏 属性?还是我必须手动访问它:即减少Object.getOwnPropertyNames(object.__proto__)


PS:或者换句话说,Chrome是如何处理隐藏属性的?

【问题讨论】:

  • 您正在寻找的是一个 foreach 循环,请参阅此线程:stackoverflow.com/questions/7440001/…
  • 至少在 Chrome 上,我的更新应该输出 object 几乎和开发者控制台一样。
  • 您无法访问隐藏的属性,这就是它们被隐藏的原因。 Chrome 显示它是因为调试器比 JS 单独可以做的更强大,并且它以令人困惑的名称 __proto__ 显示它,表明它是一个普通属性。 (也就是说,您可以通过Object.getPrototypeOf 访问原型,但一般无法访问隐藏属性。

标签: javascript object prototype


【解决方案1】:

如上所述,可以使用递归

// function to print all attributes for some object 
function getPropertyNames (Obj, prev = []) {
  if (Obj) {
    return getPropertyNames(
      Obj.prototype || Obj.__proto__, 
      prev.concat(Object.getOwnPropertyNames(Obj))
    )
  }
  return prev.sort()
}

【讨论】:

    【解决方案2】:

    你可以写一个函数,我们称它为getAllPropertyNames(),它遍历对象的原型链并累积每一层的属性:

    function getAllPropertyNames (o) {
      let propertyNames = []
    
      for (let proto = o; proto !== null; proto = Object.getPrototypeOf(proto)) {
        propertyNames = propertyNames.concat(Object.getOwnPropertyNames(proto))
      }
    
      return propertyNames
    }
    
    console.log(getAllPropertyNames({ mykey: 'value' }))

    这些属性没有隐藏,它们只是继承,这就是getOwnPropertyNames() 不包含它们的原因。它们并非特定于对象,而是继承自 Object.prototype 的所有内容。

    更新

    我将尝试一些非常规的东西,但应该会产生所需的输出:

    // probably could be named better
    // feel free to suggest one in comments
    function asEnumerable (o) {
      const acc = Object.create(null)
    
      for (let oProto = o, aProto = acc; oProto !== null; oProto = Object.getPrototypeOf(oProto), aProto = aProto.__proto__) {
        for (const key of Object.getOwnPropertyNames(oProto)) {
          aProto[key] = oProto[key]
        }
    
        if (Object.getPrototypeOf(oProto) !== null) {
          aProto.__proto__ = Object.create(null)
        }
      }
    
      return acc
    }
    
    console.log(asEnumerable({ mykey: 'value' }))
    .as-console-wrapper{min-height:100%!important}

    此实现确实遵守规范,因为它不会将__proto__ 视为修改对象的继承,而只是将其视为accaProto 上的普通属性。

    【讨论】:

    • 只需使用Object.getPrototypeOf 而不是已弃用的__proto__
    • @Bergi Object.getPrototypeOf 不允许将 __proto__ 重新配置为 enumerable。由于我已经在该示例中使用了Object.defineProperty(..., '__proto__', ...),因此在其他情况下尝试避免它是没有意义的。
    • 在不继承自Object.prototype 的对象中,您可以像使用任何其他属性一样使用__proto__,甚至不需要显式地使其可枚举。这不是已弃用的 __proto__ getter/setter,您仍然应该避免使用它。
    猜你喜欢
    • 1970-01-01
    • 2017-03-05
    • 1970-01-01
    • 2011-12-09
    • 2017-07-12
    • 2012-03-20
    • 2019-09-13
    • 1970-01-01
    相关资源
    最近更新 更多