Как ключевое слово ‘this’ работает в map() и call()?

#javascript #arrays #dictionary #this #call

#javascript #массивы #словарь #это #вызов

Вопрос:

Я обновил свои знания о call() и map() использовании JavaScript на NodeList .

Было довольно легко найти в Google, что call() следует делать, и есть ресурсы с примерами того, как это работает с map() .

Однако, как я заметил в MDN, map() функция также может принимать второй аргумент, который должен задавать this ключевое слово для map() — или, по крайней мере, это то, что я думаю, что это должно делать.

Я попытался проверить это сам с помощью простых массивов:

 var numbers = [1, 2, 3];
var letters = ['a', 'b', 'c'];
  

..и с помощью простой функции, которая будет передана в качестве параметра для map() :

 var effector = function (x) {
    console.log(x);
}
  

Теперь, чего я не понимаю, так это почему эти два вызова функции дают разные результаты:

 numbers.map(effector, letters);
numbers.map.call(letters, effector);
  

Я ожидаю, что они оба будут выводить буквы на консоль, поскольку оба this ключевых слова должны ссылаться на них (соответственно на их объекты).

Я провел некоторые дальнейшие исследования и попробовал использовать эту модифицированную эффекторную функцию:

 var effector = function () {
    console.log(this);
}
  

..снова на:

 numbers.map(effector, letters);
numbers.map.call(letters, effector);
  

Предполагая, что мы находимся в режиме «использовать строго», первый вызов регистрируется letters , а второй регистрируется undefined .

Но опять же, я бы ожидал, что оба этих вызова выдадут одинаковый результат.

Чего мне не хватает?

Редактировать:

Я читал, как .map может быть заполнено, если вы проверите это в MDN, там вы увидите, как используется второй параметр .map в callback.call() .

Я полагаю, что в конце концов даже это callback.call() должно иметь то же самое, this что и в .map .

MDN — map

Комментарии:

1. Я ожидаю, что они будут иметь одинаковые результаты, без какой-либо возможной разницы. Однако я должен выделить это в сообщении.

2. примечание: вы также можете изменить this с помощью .bind() метода

Ответ №1:

Здесь используются две привязки this ссылки:

  • this для контекста выполнения map функции
  • this для контекста выполнения функции обратного вызова

Они не связаны друг с другом.

Второй аргумент map диктует, что this будет для обратного вызова. Если оно не указано, по умолчанию используется undefined (не массив).

Первый аргумент map.call определяет, что this будет для map — и, следовательно, какой массив будет повторен.

Это также отражено в polyfill, предоставленном в mdn: он идеально соответствует этим спецификациям: O получает значение this для map функции и T получает значение this для обратного вызова. Они, как правило, разные.

map против forEach

Не имеет отношения к вашему вопросу, но стоит упомянуть: не используйте, map когда вы на самом деле ничего не отображаете. map предназначено для создания нового массива, в котором каждое значение было сопоставлено путем вызова функции обратного вызова для исходного значения с тем же индексом.

Однако, когда вам просто нужно выполнить итерацию значений массива без какого-либо намерения выполнить такое сопоставление, используйте forEach метод или for...of цикл. Оба они работают NodeList из коробки, без необходимости .call .

Комментарии:

1. Вы пришли туда примерно за минуту до меня 🙂 (и выразили это гораздо яснее, чем я)

2. Спасибо, что попытались разъяснить использование карты и ответить на мой вопрос, но не могли бы вы, пожалуйста, проверить мою правку? Я, наверное, понимаю ваш ответ, но я думаю, что есть что-то большее. Я знаю о возвращаемом значении .map, я был сосредоточен на нем, потому что скоро я начну изучать React, и я знаю, что map используется для возврата JSX, а не для forEach. И я не хотел менять свой вопрос на forEach, так как хотел избежать возможных новых проблем из-за различий map / forEach.

3. Я прочитал вашу правку, но я не вижу ничего в polyfill, что не соответствует моему ответу. Переменная T не определена, если map не получен второй аргумент: в этом случае T становится этим значением. T будет this значением для обратного вызова (только). Это то, что я говорю в своем ответе: это this не имеет ничего общего с тем, this с помощью которого map вызывается само.

4. Практическое использование полностью зависит от программиста: это удобство, которое предлагается. Это может быть полезно, когда такое map вызывается в методе класса, где вы хотите, чтобы обратный вызов имел this ссылку на этот экземпляр класса, чтобы он мог вызывать другие методы класса с this.method обозначением.

5. Обратите внимание, что все аргументы функции являются локальными переменными в этой функции. Это общий принцип.

Ответ №2:

Разница между numbers.map(effector, letters) и numbers.map.call(letters, effector) заключается в том, на какую функцию this letters установлено значение.

Во-первых, как объясняет MDN, второй аргумент — это значение, которое нужно использовать как this внутри обратного вызова, то есть аргумент, предоставленный map . То есть в numbers.map(effector, letters) this inside effector будет letters . Поскольку effector (в первой версии) не имеет значения, что this есть, этот аргумент по существу не имеет никакого эффекта, и содержимое numbers регистрируется.

В numbers.map.call(letters, effector) , с другой стороны, это то, numbers.map для this которого letters установлено значение. Что фактически означает, что map метод, хотя и вызывается numbers , вместо этого «захвачен» для регистрации записей letters .

Второй пример работает аналогично — решающее значение имеет то, в какой функции this установлен effector : numbers.map в одном случае,, в другом.

Комментарии:

1. Я поддержал вас, поэтому, даже если вы не будете показаны выше предыдущего ответа, вы можете заработать некоторую репутацию. Как я прокомментировал в предыдущем ответе, может быть что-то более неясное с использованием map, не могли бы вы, пожалуйста, проверить «РЕДАКТИРОВАТЬ» в конце моего вопроса?