使用 Object.create(null) 创建 JS 对象是否与 {} 相同?

IT技术 javascript
2021-01-20 14:01:58

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

问题:

是不是完全一样:

var p = {}

对比

var p2 = Object.create(null);

?

5个回答

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

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

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


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

在此处输入图片说明

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

  1. var p = {};

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

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

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

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

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

请注意,可以将某些内容分配给p.toString,它会简单地覆盖 上的继承toString函数p

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

另一方面,如果您使用上面的方法2,那么您就不必担心Object地图中出现的东西

你不能用这样的简单检查属性的存在if

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

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

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

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

如果有人正在寻找实施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;
}

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

此外,第二个参数应该描述属性描述符而不是实际属性本身。请参阅此处的参考:developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/...
2021-03-22 14:01:58
为什么-1arguments.length>0?arguments[0]:-1;
2021-03-23 14:01:58
请注意,ECMAScript 在夏季发布时,__proto__正式成为该语言的一部分。
2021-03-24 14:01:58
@happy_marmoset 延迟响应,但它看起来只是一个非空占位符,因此Object如果未给出第一个参数,则保留原型。变量名在这里可能会好很多。
2021-03-28 14:01:58

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