【问题标题】:`new Object` vs `Object` in the ECMAScript specECMAScript 规范中的 `new Object` 与 `Object`
【发布时间】:2015-08-28 08:54:03
【问题描述】:

所以,我正在查看 ES5 规范中 new ObjectObject 所做的定义。令我惊讶的是:

  • new Object 描述了对象构造函数如何工作的整个算法——处理不同类型的值会发生什么。基本上在非对象上调用 ToObject - 对象上的标识并建立在 null 和 undefined 上。
  • Object 对 null 和 undefined 有一个特殊的第一步,它在其中构建一个对象,然后在原语上调用 ToObject 在对象上调用身份。

在阅读了几次描述之后 - 它们似乎一模一样。然而,从规范中可以明显看出他们做了一些不同的事情。例如在Array - 调用new Array 被指定为 the function call Array(…) is equivalent to the object creation expression new Array(…) with the same arguments.`

那么 - new ObjectObject 有什么区别?为什么它们的指定不同?

为方便起见 - 这是link to the spec

【问题讨论】:

  • JS 房间的人(即 Jan Drovak)猜测它与宿主对象有关,但我无法找出真正产生影响的一个。
  • new Object 是在宿主对象上实现定义的。我仍然希望看到它不是身份的示例。
  • 这会是那些著名的问题之一吗?
  • When Object is called as part of a new expression, it is a constructor that may create an object. 涉及If the value is a host object, then actions are taken and a result is returned in an implementation-dependent manner that may depend on the host object.,这取决于实现。 ToObject - Object: The result is the input argument (no conversion). 这似乎是主要区别。为什么?可能允许implementation dependant 部分
  • 为什么不在esdiscuss.org上提问?

标签: javascript language-lawyer ecmascript-5


【解决方案1】:

Object(window) 永远不会克隆 window,但 new Object(window) 可能。尽管规范允许实现定义的行为,但所有当前的(可能是所有已知的)实现都只返回相同的引用。

15.2.1.1 的步骤说:

  1. 如果 value 为 null、未定义或未提供,则创建并返回一个新的 Object 对象,就像使用相同的参数调用标准内置 Object 构造函数一样
  2. 返回对象(值)。

ToObject (9.9) 的定义列出了一些将被步骤 1 捕获的类型(在表 14 中),但对于 Object 有一个非常简单的定义:

结果是输入参数(没有转换)。

它明确指出输入参数将按原样返回,因此它们应该是相等的引用 (===)。

new Object (15.2.2.1) 的定义在步骤 1 中具有类似的类型检查链,但对象 (1.a) 的步骤是:

我。如果该值是原生 ECMAScript 对象,则不要创建新对象而只是返回值。

二。如果该值是宿主对象,则执行操作并以可能依赖于宿主对象的实现相关方式返回结果。

也就是说,对于任何主机对象foo,调用Object(foo) 必须=== foonew Object(foo) 可能=== foo

主机对象在 4.3.8 中定义为

宿主环境提供的对象,用来完成ECMAScript的执行环境。

This answer 列出了一些主机对象,包括windowhistory 等。通过new Object(foo) 运行这些对象应该(但不是必须)返回不同的对象。

在任何情况下但是传递一个宿主对象,new Object(foo) 似乎是一个更复杂的链,它遵循ToObject 的方式与Object(foo) 大致相同。

不幸的是,15.2.2.1.1.a.ii 声明“结果以依赖于实现的方式返回”并且没有具体说明“所采取的操作”,Chrome 似乎会返回所有列出的“宿主对象”都使用相同的对象(相同的引用)。

使用此脚本检查:

var objects = [
  /* Native objects */
  'Object', 'Date', 'Math', 'parseInt', 'eval',
  /* Host objects */
  'window', 'document', 'location', 'history', 'XMLHttpRequest', 'setTimeout'
];

function getDefinedReference(name) {
  if (eval('typeof ' + name) !== 'undefined') {
    return eval(name);
  } else {
    throw new Error('' + name + ' is not defined.');
  }
}

function checkIdentity(name) {
  try {
    var ref = getDefinedReference(name);
    var no = new Object(ref);
    var o = Object(ref);

    console.log(name, ref === no, ref === o, no === o);

    if (ref === o && no !== o) {
      // Make sure ref === Object(ref) but not new Object(ref)
      console.log(name, 'returns different references.');
    }
  } catch (e) {
    console.warn(e);
  }
}

objects.forEach(checkIdentity);

if (typeof window !== 'undefined') {
  for (var f in window) {
    checkIdentity(f);
  }
}

没有找到任何 Objectnew Object 行为不同的对象。 @Xotic750 似乎是正确的,它可以依赖于实现,但没有人使用它。

【讨论】:

  • 你能找到Objectnew Object之间不同的一种实现和一种宿主对象吗?
  • @BenjaminGruenbaum 仍在寻找。我强烈怀疑这是规范允许但没有人使用的东西,但测试套件不会受到伤害。
  • @AwalGarg 两个新创建的对象引用不相等 - 与{} === {}相同
  • @AwalGarg 整个问题依赖于第二部分,它不是 null/undefined :-)
猜你喜欢
  • 2014-05-14
  • 1970-01-01
  • 2012-06-02
  • 2011-07-13
  • 2012-03-10
  • 1970-01-01
  • 2014-02-10
  • 2014-06-21
相关资源
最近更新 更多