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

Почему функции прототипа MDC написаны таким образом?

В MDC есть много фрагментов кода, которые предназначены для реализации поддержки новых стандартов ECMAScript в браузерах, которые их не поддерживают, например, Array.prototype.map:

if (!Array.prototype.map)
{
  Array.prototype.map = function(fun /*, thisp */)
  {
    "use strict";

    if (this === void 0 || this === null)
      throw new TypeError();

    var t = Object(this);
    var len = t.length >>> 0;
    if (typeof fun !== "function")
      throw new TypeError();

    var res = new Array(len);
    var thisp = arguments[1];
    for (var i = 0; i < len; i++)
    {
      if (i in t)
        res[i] = fun.call(thisp, t[i], i, t);
    }

    return res;
  };
}

Какая польза (если есть) использования этой функции, а не

function(fun, thisp)
{
  // same code, just without the "var thisp = arguments[1];" line:
  "use strict";

  if (this === void 0 || this === null)
    throw new TypeError();

  var t = Object(this);
  var len = t.length >>> 0;
  if (typeof fun !== "function")
    throw new TypeError();

  var res = new Array(len);
  for (var i = 0; i < len; i++)
  {
    if (i in t)
      res[i] = fun.call(thisp, t[i], i, t);
  }

  return res;
}

var t = Object(this);, а не var t = this; и var len = t.length >>> 0;, а не var len = t.length;?

4b9b3361

Ответ 1

var len = t.length >>> 0;    

Это было довольно хорошо описано в этом вопросе. В основном это гарантирует, что число является неотрицательным 32-битным int.

Что касается конструктора Object:

var t = Object(this);

Если это null или undefined, он вернет пустой объект. Из Документы MDC по объекту

Конструктор объекта создает обертка объекта для данного значения. Если значение равно null или undefined, оно создаст и вернет пустую объект, в противном случае он вернет объект типа, который соответствует заданное значение.

Они оба - просто быстрые способы исправления ошибок.

EDIT: Я слишком сильно думал об этой части. Я предполагал, что использование массива arguments было способом обеспечения того, чтобы аргументы не выполнялись до undefined, но они все равно делают это самостоятельно. Майк Хофер понял это в комментариях. Это стиль кодировки Mozilla для указания необязательных параметров. Function.call по умолчанию принимает значение global, если в качестве первого аргумента передается значение null или undefined. Из MDC Docs на Function.call

thisArg: Определяет значение этого внутри весело. Если thisArg имеет значение null или undefined, этот будет глобальным объектом. В противном случае этот будет равен Object (thisArg) (который является thisArg if thisArg уже является объектом или String, Boolean или Number, если thisArg является примитивным значением соответствующий тип). Следовательно, это всегда true, что typeof this == "объект", когда функция выполняет.

Ответ 2

var t = Object(this);

Основан на спецификации ES5. В нем указано, что this следует передать в конструктор Object.

Если вы внимательно посмотрите на точный алгоритм, указанный в спецификации ES5, то метод, предоставляемый Mozilla, зеркалирует его почти точно (он ограничен функциями ES3). Вот почему этот код, кажется, имеет несколько особенностей.

Вот спецификация ES5:

Когда метод карты вызывается с одним или два аргумента, следующие шаги взяты:

  • Пусть O - результат вызова ToObject, передающего это значение в качестве аргумента.
  • Пусть lenValue является результатом вызова внутреннего метода O [[Get]] с аргументом "length".
  • Пусть len - ToUint32 (lenValue).
  • Если IsCallable (callbackfn) является ложным, введите исключение TypeError.
  • Если thisArg был предоставлен, пусть T - этоArg; иначе пусть T будет undefined.
  • Пусть A - новый массив, созданный, как если бы выражение new Array (len), где Array - стандартный встроенный конструктор с этим именем, а len - значение len.
  • Пусть k равно 0.
  • Повторите, в то время как k < Len

    • Пусть Pk - ToString (k).
    • Пусть kPresent является результатом вызова внутреннего метода O [[HasProperty]] с аргументом Pk.
    • Если kPresent истинно, тогда
      • Пусть kValue является результатом вызова внутреннего метода [[Get]] O с аргументом Pk.
      • Пусть mappedValue является результатом вызова внутреннего метода callbackfn [[Call]] с T как это значение и список аргументов, содержащие значения kValue, k и O.
      • Вызвать внутренний метод [[DefineOwnProperty]] A с аргументами Pk, Свойство Дескриптор {[[Value]]: mappedValue, [[Writable]]: true, [[Enumerable]]: true, [[Configurable]]: true} и false.
      • Увеличить k на 1.
  • Вернуть A.

Пусть O - результат вызова ToObject, передающего это значение в качестве аргумента.

Обратите внимание, что на первом этапе вы говорите, что вы должны называть Object(this)

Пусть lenValue будет результатом вызова внутренний метод [[Get]] O аргумент "длина".

Пусть len be ToUint32 (lenValue).

Шаг 2 и 3, скажем, получите t.length, затем вызовите ToUint32, который реализован здесь как >>> 0.

Фактическая подпись, указанная в спецификации,

Array.prototype.map(callbackfn [, thisArg])

В приведенной выше сигнатуре callbackfn является обязательным аргументом, а [ ] является массивом необязательных аргументов, который содержит только один thisArg.

Mozilla отразила это в своем определении function(fun /*, thisp */) {, чтобы указать, что thisp является необязательным аргументом, и он очищает это от сигнатуры функции, а не от просмотра кода.