【问题标题】:Is creating JS object with Object.create(null) the same as {}?用 Object.create(null) 创建 JS 对象和 {} 一样吗?
【发布时间】:2013-03-20 08:12:35
【问题描述】:

我知道很多创建 JS 对象的方法,但我不知道 Object.create(null) 的方法。

问题:

是否完全一样:

var p = {}

var p2 = Object.create(null);

?

【问题讨论】:

    标签: javascript


    【解决方案1】:

    它们不等价。 {}.constructor.prototype == Object.prototypeObject.create(null) 不继承任何东西,因此根本没有任何属性。

    换句话说:javascript 对象默认继承自 Object,除非您明确创建它时使用 null 作为其原型,例如:Object.create(null)

    {} 将等效于 Object.create(Object.prototype)


    在 Chrome Devtool 中,您可以看到 Object.create(null) 没有 __proto__ 属性,而 {} 有。

    【讨论】:

      【解决方案2】:

      它们绝对不是等价的。我写这个答案是为了更全面地解释为什么它会有所作为。

      1. var p = {};

        创建一个从Object 继承属性和方法的对象。

      2. var p2 = Object.create(null);

        创建一个不继承任何东西的对象。

      如果您将对象用作地图,并且使用上述方法 1 创建了对象,则在地图中查找时必须格外小心。因为来自Object 的属性和方法是继承的,所以您的代码可能会遇到映射中存在您从未插入的键的情况。例如,如果您在toString 上进行了查找,您会找到一个函数,即使您从未将那个值放在那里。你可以像这样解决这个问题:

      if (Object.prototype.hasOwnProperty.call(p, 'toString')) {
          // we actually inserted a 'toString' key into p
      }
      

      请注意,可以给p.toString 赋值,它只会覆盖p 上继承的toString 函数。

      请注意,您不能只使用p.hasOwnProperty('toString'),因为您可能已将密钥“hasOwnProperty”插入p,因此我们强制它使用Object 中的实现。

      另一方面,如果你使用上面的方法2,那么你就不用担心Object会出现在地图上。

      您无法使用简单的if 来检查属性是否存在,如下所示:

      // Unreliable:
      if (p[someKey]) {
          // ...
      }
      

      该值可能是一个空字符串,可能是false,或null,或undefined,或0,或NaN,等等。要检查一个属性是否存在,你会仍然需要使用Object.prototype.hasOwnProperty.call(p, someKey)

      【讨论】:

      • 检查属性是否存在的更简单的替代方法是:if (someKey in p) {
      • @mrcrowl 仅当他们使用 Object.create(null) 时。我不想做这样的假设,即使你完全正确地认为它使用了Object.create(null),代码可能会改变,对象可能会被替换为在某些时候继承Object 的对象。 hasOwnProperty 始终有效。
      • 我觉得对这样的事情要小心是没有必要的。感谢您的回答,但文档应该为您提供使用您正在使用的任何代码所需的 api。如果您从 github 获取一些随机代码,那么您可以分叉它并避免文档较少的更新。更不用说{}Object.create(null) 更普遍,如果您的代码此时意外地获取了继承的属性,您可能需要担心更大的错误。我只能看到人们使用 Object.create(null) 作为次要优化。
      • 双重否定 !!p[key] 适用于 Object.create(null)。不过hasKey = (key, input) => Object.prototype.hasOwnProperty.call(input, key)也不错
      • > 注意你不能只做 p.hasOwnProperty('toString') 因为你可能在 p 中插入了一个键“hasOwnProperty”,所以我们强制它使用 Object 中的实现。那是不必要的。在这种情况下,您不能使用p 中的任何方法,因为每个方法都可以插入,因此变得不安全。
      【解决方案3】:

      使用{}创建对象将创建一个原型为Object.prototype的对象,它继承了Object原型的基本功能,而使用Object.create(null)创建对象将创建一个原型为null的空对象。

      【讨论】:

        【解决方案4】:

        如果有人正在寻找实现Object.create(null),只是想知道它是如何工作的。它是使用非标准的__proto__ 编写的,因此,我不推荐它

        function objectCreateMimic()
        {
          /*optional parameters: prototype_object, own_properties*/
          var P = arguments.length>0?arguments[0]:-1;
          var Q = arguments.length>1?arguments[1]:null;
          var o = {};
          if(P!==null && typeof P === "object")
          {
            o.__proto__ = P;
          }
          else if(P===null)
          {
            o.__proto__ = null;
          }
          if(Q!==null && typeof Q === "object")
          {
           for(var key in Q)
           {
             o[key] = Q[key];
           }
          }
          return o;
        }
        

        注意:出于好奇,我写了这个,而且只是用简单的术语来写,例如,我没有将属性描述符从第二个对象转移到返回对象。 p>

        【讨论】:

        • 请注意,在夏季 ECMAScript 发布时,__proto__ 现在将 officially 成为该语言的一部分。
        • 为什么 -1arguments.length>0?arguments[0]:-1;
        • @happy_marmoset 延迟响应,但看起来它只是一个非空占位符,因此如果未给出第一个参数,则保留 Object 原型。这里的变量名可能会好很多。
        • 另外,第二个参数应该描述属性 descriptors 而不是实际属性本身。在此处查看参考:developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
        【解决方案5】:

        当您使用 Object.create(null) 创建一个对象时,这意味着您正在创建一个没有原型的对象。null 此处表示原型链的结束。然而,当您创建像 {} 这样的对象时,将添加对象原型。 因此,这是两个不同的对象,一个有原型另一个没有原型。希望这会有所帮助

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2017-12-17
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多