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

sgtfey8w  于 2022-12-17  发布在  Java
关注(0)|答案(6)|浏览(92)

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

问题:

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

var p = {}

对比

var p2 = Object.create(null);

oxosxuxt

oxosxuxt1#

它们不是等价的. {}.constructor.prototype == Object.prototype,而Object.create(null)不继承任何东西,因此根本没有属性。
换句话说:默认情况下,javascript对象继承自Object,除非您显式创建它时使用null作为原型,例如:Object.create(null) .
{}将改为等效于Object.create(Object.prototype)
在Chrome Devtool中,您可以看到Object.create(null)没有__proto__属性,而{}有。

q5lcpyga

q5lcpyga2#

它们肯定不等同,我写这个答案是为了更全面地解释为什么会有区别。

  1. var p = {};
    创建从Object继承属性和方法的对象。
  2. var p2 = Object.create(null);
    创建不继承任何内容的对象。
    如果将对象用作Map,并使用上面的方法1创建对象,则在Map中查找时必须格外小心。因为Object的属性和方法是继承的,所以代码可能会遇到Map中存在从未插入的键的情况。例如,如果在toString上查找,则会发现函数即使你从来没有把这个值放在那里。你可以这样做:
if (Object.prototype.hasOwnProperty.call(p, 'toString')) {
    // we actually inserted a 'toString' key into p
}

注意,可以给p.toString赋值,它只会覆盖p上继承的toString函数。
请注意,您不能只执行p.hasOwnProperty('toString'),因为您可能已经在p中插入了一个键“hasOwnProperty”,所以我们强制它使用Object中的实现。
另一方面,如果使用上面的方法2,则不必担心Object的内容会出现在Map中。
您无法使用简单的if检查属性是否存在,如下所示:

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

该值可以是空字符串,也可以是falsenullundefined0NaN等。要检查属性是否存在,仍需要使用Object.prototype.hasOwnProperty.call(p, someKey)

h6my8fg2

h6my8fg23#

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

oxcyiej7

oxcyiej74#

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

注意:我写这段代码是出于好奇,而且只写了一些简单的术语,例如,我没有把属性描述符从第二个对象转移到返回对象。

tktrz96b

tktrz96b5#

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

kzipqqlq

kzipqqlq6#

这是一个老问题,似乎所有的答案都是有效的,但@Royi Namir可能也是在暗示什么,这里最好理解的是我应该使用它吗?而不是仅仅问这个问题,我会甘德。

  • {}是简单、直接且众所周知的普遍存在的代码。
  • Object.create(null)不太为人所知,也不太常用,我们可以从所提问题的纯粹事实中推测出这一点。

为什么要使用Object.create(null)而不是{}?这里的其他答案通过指出这两种方法之间的区别来回答这个问题,区别很简单,Object.create(null)不继承Object.prototype prototype,而{}继承Object.prototype prototype,这在您的特定环境中可能很有价值。
除此之外,您可能希望使用其中一个而不是另一个的唯一原因是性能、内存使用或易用性。
如果我们运行一些简单的测试来测量两种方式创建对象所花费的时间,我们可以看到确实存在性能和内存差异。* 注意:为了简化我的评论,我只展示了包括属性赋值的测试,但是我已经完成了有属性赋值和没有属性赋值的测试,并且指标是相似的。*

console.time("create curly");
let objects = [];
for (let i = 0; i < 100000; i++) {
    objects.push({ attr1: i, attr2: i*2, attr3: i*5});
}
console.log(objects.length);
console.timeEnd("create curly");
console.log("Memory", process.memoryUsage().heapUsed);

输出(多次运行、最佳时间、不精确):
x一个一个一个一个x一个一个二个x
输出(多次运行、最佳时间、不精确):

create object: 41.106ms
Memory 23766400

性能虽然时间输出不是一个完全科学、精确的度量标准,但我认为可以很有把握地说,Object.create(null){}慢。但是,根据需要创建的对象数量,这可能是一个相对无关紧要的差异。
内存从所示的测试结果来看,使用Object.create(null)创建对象并为对象分配一些属性所需的内存是使用{}创建对象并内联属性所需内存的两倍。对于100,000个对象,大约多10 MB。这是非常重要的!
易用性显而易见,具有内联属性的{}明显更易于使用,并且允许简化属性分配。

总之,使用{}是为了获得更好的性能、内存使用和减轻手指压力,除非您有真实的的理由创建不继承Object.prototype原型的对象。

相关问题