Подтвердить что ты не робот

`new Object` vs` Object` в спецификации ECMAScript

Итак, я рассматриваю спецификацию ES5 при определении того, что делают new Object и Object. К моему удивлению,

  • new Object описывает целый алгоритм работы конструктора объектов - обработку того, что происходит с разными типами значений. В основном вызывает ToObject для не-объектов - идентификация объектов и строит на null и undefined.
  • Object имеет специальный первый шаг для null и undefined, где он создает объект, а затем вызывает ToObject для примитивов и идентификаторов объектов.

Прочитав описание несколько раз - они кажутся одинаковыми. Однако, очевидно, из спецификации они делают что-то другое. Например, в Array - вызов new Array указан как вызов функции Array(…) эквивалентен выражению создания объекта new Array(…) с теми же аргументами.

Итак - какая разница между new Object и Object? Почему они были заданы по-разному?

Для удобства - здесь ссылка на спецификацию.

4b9b3361

Ответ 1

Object(window) никогда не будет клонировать window, но new Object(window) может. Все текущие - потенциально все известные - реализации просто возвращают одну и ту же ссылку, хотя спецификация допускает поведение, определяемое реализацией.

Шаги для 15.2.1.1 говорят:

  • Если значение равно null, undefined или не указано, создайте и верните новый объект Object точно так же, как если бы стандартный встроенный конструктор Object был вызван с теми же аргументами
  • Return ToObject (значение).

В определении ToObject (9.9) перечислены несколько типов, которые будут пойманы на шаге 1 (в таблице 14), но для Object имеет очень простое определение:

Результат - входной аргумент (без преобразования).

В нем явно указано, что входной аргумент будет возвращен как-is, поэтому они должны быть равными ссылками (===).

Определение для new Object (15.2.2.1) имеет аналогичную цепочку проверок типов на шаге 1, но шаг для объектов (1.a):

я. Если значение является родным объектом ECMAScript, не создавайте новый объект, а просто возвращайте значение.

II. Если значение является объектом-хозяином, тогда предпринимаются действия и результат возвращается зависимым от реализации образом, который может зависеть от объекта-хоста.

То есть для любого объекта-хоста foo вызов Object(foo) должен === foo, но new Object(foo) может === foo.

Объекты хоста определены в 4.3.8 как

предоставленный средой хоста для завершения среды выполнения ECMAScript.

В этом ответе перечислены несколько объектов-хостов для включения window, history и т.д. Запуск этих объектов через new Object(foo) должен (но не должен ) возвращает другой объект.

В любом случае, но передавая объект-хост, new Object(foo) представляется более сложной цепочкой, которая отбрасывает ToObject во многом так же, как Object(foo).

К сожалению, в 15.2.2.1.1.a.ii указано, что "результат возвращен зависимым от реализации образом" и не имеет каких-либо особенностей относительно "действий [которые] приняты", и кажется, что Chrome вернется один и тот же объект (равные ссылки) для всех перечисленных "объектов хоста".

Используя этот script, чтобы проверить:

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);
  }
}