Автор оригинала: FreeCodeCamp Community Member.
Pradeep Pothineni
JavaScript сейчас вездесущий язык. После использования на стороне клиента, теперь вы можете найти его на серверах во многих ароматах. Как вырос JavaScript, так и его арсенал функций, которые пользователи могут использовать. В большинстве случаев вы являетесь контером, используя эти методы, и только редко вы хотите взять этот дополнительный шаг, чтобы понять, что на самом деле происходит под капотом.
На этой записке давайте сделаем этот дополнительный шаг сегодня и исследовать очень популярную функцию: Array.prototype.map () Отказ
Отказ от ответственности : Я не буду объяснять, как использовать карта () – Пример ниже иллюстрирует его, или вы можете найти многочисленные примеры при Google. Вместо этого давайте останавливаемся, как карта фактически реализована за кулисами.
карта () Метод создает новый массив с результатом вызова прилагаемой функции на каждом элементе в массиве вызова.
Пример:
var array1 = [1, 4, 9, 16]; // pass a function to map const map1 = array1.map(x => x * 2); console.log(map1); // expected output: Array [2, 8, 18, 32]
Реализация
Давайте выберем реализацию прямо от рта лошади и попробуйте рассекать его. Ниже приведен полифилл MDN. Проведите некоторое время, понимая код и скопируйте его и запустите его на своей машине. Если вы являетесь новичком/промежуточным разработчиком JavaScript, вы обязательно столкнетесь с несколькими парами вопросов.
/*Array.prototype.map implementation*/
Array.prototype.map = function (callback/*, thisArg*/) {
var T, A, k;
if (this == null) {
throw new TypeError('this is null or not defined');
}
var O = Object(this);
var len = O.length >>> 0;
if (typeof callback !== 'function') {
throw new TypeError(callback + ' is not a function');
}
if (arguments.length > 1) {
T = arguments[1];
}
A = new Array(len);
k = 0;
while (k < len) {
var kValue, mappedValue;
if (k in O) {
kValue = O[k];
mappedValue = callback.call(T, kValue, k, O);
A[k] = mappedValue;
}
k++;
}
return A;
};Я подчеркнул несколько общих вопросов, которые могут возникнуть в кодовых комментариях ниже.
/*Array.prototype.map implementation*/
Array.prototype.map = function (callback/*, thisArg*/) {
var T, A, k;
if (this == null) {
throw new TypeError('this is null or not defined');
}
var O = Object(this);
var len = O.length >>> 0;// QUESTION 1 : What is the need for this line of code?
if (typeof callback !== 'function') {
throw new TypeError(callback + ' is not a function');
}
if (arguments.length > 1) {
T = arguments[1];
}
// QUESTION 2 :What is the need for the if condition and why are we assiging T=arguments[1]?
A = new Array(len);
k = 0;
while (k < len) {
var kValue, mappedValue;
if (k in O) {
kValue = O[k];
mappedValue = callback.call(T, kValue, k, O);
// QUESTION 3: why do we pass T,k and O when all you need is kvalue?
A[k] = mappedValue;
}
k++;
}
return A;
};Давайте обратимся к каждому из них, начиная с дна
Вопрос 3: Почему мы проходим T, K и O, когда все, что вам нужно, это Kvalue?
mappedValue = callback.call(T, kValue, k, O);
Это самый простой из трех вопросов, поэтому я выбрал это, чтобы начать. В большинстве случаев проходя Квале к Обратный вызов было бы достаточно, но:
- Что, если у вас есть случай, когда вам нужно выполнить операцию только на каждом другом элементе? Ну, вам нужен индекс, который является (k) Отказ
- Точно так же могут быть другие случаи использования, где вам нужен массив (O) сам быть доступен в обратном вызове.
- Почему Т ? Пока просто знаю, что T проходит вокруг, чтобы поддерживать контекст. Вы поймете это лучше, как только вы закончите с вопросом 2.
Вопрос 2: Что такое необходимость в состоянии, и почему мы присваиваем [1]?
if (arguments.length > 1) { T = arguments[1]; }Функция карты в вышеупомянутой реализации имеет два аргумента: Обратный вызов и необязательно thisarg Отказ Обратный вызов – обязательный аргумент, тогда как thisarg не является обязательным.
Можно пройти, что должно быть «Это» Значение внутри Обратный вызов предоставляя второй необязательный аргумент. Вот почему код проверяет, есть ли более одного аргумента и присваивает второй дополнительный аргумент для переменной, которую можно передавать обратным вызовам.
Чтобы проиллюстрировать лучше, скажем, у вас есть требование о макере, где вам нужно вернуть номер 2 Если он делится на 2, и если он не делится на 2, вам нужно вернуть имя пользователя вызывающего человека. Код ниже иллюстрирует, как вы можете сделать это:
const myObj = { user: "John Smith" }
var x = [10, 7];
let output = x.map(function (n) {
if (n % 2 == 0) {
return n / 2;
} else {
return this.user
}
}, myObj) // myObj is the second optional argument arguments[1]
console.log(output); // [5,'John Smith']
//if you run the program without supplying myObj it would be //undefined as it cannot access myObj values
console.log(output); // [ 5, undefined ]Вопрос 1: Что такое необходимость в этой строке кода?
var len = O.length >>> 0
Это заняло некоторое время для меня, чтобы выяснить. Есть много в этой строке кода. В JavaScript у вас есть возможность переопределить «Это» в рамках функции, вызывая метод, используя вызов Отказ Вы можете сделать это, используя привязывать или Применить Кроме того, но для этого обсуждения давайте придерживаться вызов.
const anotherObject={length:{}}
const myObj = { user: "John Smith" }
var x = [10, 7];
let output = x.map.call(anotherObject,function (n) {
if (n % 2 == 0) {return n / 2;}
else
{return this.user}
}, myObj)Когда вы вызываете, используя Звоните, Первый параметр будет контекст, в котором выполняется функция карты. Отправляя параметр, вы перезаписываете «Это» Внутри карты с «Это» по очереди.
Если вы наблюдаете, Длина Свойство kerobject – это пустой объект, а не целое число. Если вы просто используете O.length вместо o.length> >> 0. Это приведет к неопределенному значению. На нуле сдвигается, вы фактически преобразуете любые фракции и незначительные числа в целое число. В этом случае результат будет принужден к 0.
Большинство случаев использования не понадобится эта проверка, но может быть обработан этот сценарий, который должен быть обработан этот вид сценария. Хорошие программисты, которые спроектировали спецификацию, действительно так думали! Говоря о спецификации, вы можете найти спецификацию о том, как каждая функция должна быть реализована в Ecmascript здесь:
Спецификация языка Ecmascript – ECMA-262 Edition 5.1 Этот документ и возможные переводы его могут быть скопированы и меблированы другим, а производные произведения, которые комментируют … www.ecma-international.org
Спецификация ( Шаг 3 ) четко говорит, что длина должна быть 32 бит без знака целого числа. Это причина, по которой мы нулевые заполните, чтобы убедиться, что длина – это целое число, так как сама карта не требует, чтобы это Значение – объект массива.
Вот и все!
Я хотел бы поблагодарить пару людей, я никогда не встречал их, но они были достаточно добрыми, чтобы занять время (в интернет-форумах) и помогите мне понять несколько нюансов.
Салатиль Генеза , Jordan Rearband – Спасибо!
ПРИМЕЧАНИЕ. Если вы застряли на другую строку кода, не стесняйтесь вкладывать это в комментарии, и я сделаю все возможное, чтобы уточнить.
Спасибо за ваше время и счастливое кодирование!