使用Object.create(null)创建JS对象?


150

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

题:

是否与以下内容完全相同:

var p = {}

var p2 = Object.create(null);

Answers:


199

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

换句话说:默认情况下,除非您以null为原型明确创建它,否则javascript对象将从Object继承,例如:Object.create(null)

{}而是等效于Object.create(Object.prototype)


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

在此处输入图片说明


99

它们绝对不是等效的。我正在写此答案,以更全面地解释为什么会有所作为。

  1. var p = {};

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

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

    创建一个不继承任何内容的对象。

如果将对象用作地图,并且使用上面的方法1创建对象,则在地图中进行查找时必须格外小心。因为from的属性和方法Object是继承的,所以您的代码可能会遇到映射中存在从未插入的键的情况。例如,如果您在上进行了查找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,或null,或undefined,或0NaN,等等。要检查某个属性是否存在,仍然需要使用Object.prototype.hasOwnProperty.call(p, someKey)


6
检查属性是否存在的一种更简单的选择是:if (someKey in p) {
mrcrowl

2
@mrcrowl仅当使用它们时Object.create(null)。我不希望做出这样的假设,即使您绝对正确地使用Object.create(null)了该代码,代码也可能会更改,该对象可能会替换为Object在某个时候继承的对象。hasOwnProperty一直有效。
doug65536 '16

1
我觉得对这样的事情要格外小心。非常感谢您的回答,但文档应为您提供使用所使用的任何代码所必需的api。如果您要从github上获取一些随机代码,则可以对其进行派生,并避免受到文档记录较少的更新。更不用说{}Object.create(null),它比如此流行得多,如果此时您的代码不小心抓住了继承的属性,则您可能有更大的bug需要担心。我只能看到人们使用Object.create(null)作为次要优化。
aaaaaa

双重否定!!p[key]可以与Object.create(null)。不过hasKey = (key, input) => Object.prototype.hasOwnProperty.call(input, key)也不错啊
andreid

>请注意,您不能只是执行p.hasOwnProperty('toString'),因为您可能已在p中插入了键“ hasOwnProperty”,因此我们强制其使用Object中的实现。没必要 在这种情况下,您不能使用任何方法,p因为每个方法都可以插入,因此变得不安全。
xianshenglu '18

1

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


0

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

注意:我出于好奇而编写了此文件,并且它仅是用简单的术语编写的,例如,我没有将属性描述符从第二个对象传输到返回对象。


1
请注意,自ECMAScript于夏季发布以来,__proto__现在将正式成为该语言的一部分。
Chiru)

1
为什么-1arguments.length>0?arguments[0]:-1;
happy_marmoset

@happy_marmoset晚响应,但看起来它只是一个非空的占位符,因此,Object如果没有给出第一个参数,则保留原型。变量名在这里可能要好得多。
Mike Hill

同样,第二个参数应描述属性描述符,而不是实际的属性本身。看到这里引用:developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/...
迈克·希尔

0

使用Object.create(null)创建对象时,这意味着您正在创建没有原型的对象。null此处表示原型链结束。但是,当您创建类似{}的对象时,将添加对象原型。因此,这是两个不同的对象,一个带有原型,另一个没有原型。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.