Почему функции прототипа 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;
?
Ответы
Ответ 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, передающего это значение в качестве аргумента.
Обратите внимание, что на первом этапе вы говорите, что вы должны называть 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
является необязательным аргументом, и он очищает это от сигнатуры функции, а не от просмотра кода.