Книга: Выразительный JavaScript
this и его область видимости
this и его область видимости
В конструкторе World
есть вызов forEach
. Хочу отметить, что внутри функции, передаваемой в forEach
, мы уже не находимся непосредственно в области видимости конструктора. Каждый вызов функции получает своё пространство имён, поэтому this
внутри неё уже не ссылается на создаваемый объект, на который ссылается this
снаружи функции. И вообще, если функция вызывается не как метод, this
будет относиться к глобальному объекту.
Значит, мы не можем писать this.grid
для доступа к сетке изнутри цикла. Вместо этого внешняя функция создаёт локальную переменную grid
, через которую внутренняя функция получает доступ к сетке.
Это промах в дизайне JavaScript. К счастью, в следующей версии есть решение этой проблемы. А пока есть пути обхода. Обычно пишут var self = this
и после этого работают с переменной self
.
Другое решение – использовать метод bind
, который позволяет привязаться к конкретному объекту this
.
var test = {
prop: 10,
addPropTo: function(array) {
return array.map(function(elt) {
return this.prop + elt;
}.bind(this));
}
};
console.log(test.addPropTo([5]));
// ? [15]
Функция, передаваемая в map
– результат привязки вызова, и посему её this
привязан к первому аргументу, переданному в bind
, то есть переменной this
внешней функции (в которой содержится объект test
).
Большинство стандартных методов высшего порядка у массивов, таких как forEach
и map
, принимают необязательный второй аргумент, который тоже можно использовать для передачи this
при вызовах итерационной функции. Вы могли бы написать предыдущий пример чуть проще:
var test = {
prop: 10,
addPropTo: function(array) {
return array.map(function(elt) {
return this.prop + elt;
}, this); // ? без bind
}
};
console.log(test.addPropTo([5]));
// ? [15]
Это работает только с теми функциями высшего порядка, у которых есть такой контекстный параметр. Если нет – приходится использовать другие упомянутые подходы.
В нашей собственной функции высшего порядка мы можем включить поддержку контекстного параметра, используя метод call
для вызова функции, переданной в качестве аргумента. К примеру, вот вам метод forEach
для нашего типа Grid
, вызывающий заданную функцию для каждого элемента сетки, который не равен null
или undefined
:
Grid.prototype.forEach = function(f, context) {
for (var y = 0; y < this.height; y++) {
for (var x = 0; x < this.width; x++) {
var value = this.space[x + y * this.width];
if (value != null)
f.call(context, value, new Vector(x, y));
}
}
};
- Ничего, кроме правды: поведение потребителей
- Роль товарной категории и установление цены
- Глава 7 Чего нужно опасаться при моделировании бизнес-процессов. Проектные риски моделирования бизнеспроцессов
- Категорийный менеджмент. Курс управления ассортиментом в рознице
- 7.4.2.4. Создание своего первого LiveCD
- Conventions used in this document
- 6.4. Рабочий лист Excel и его структурные элементы
- Why this document was written
- Terms used in this document
- Кроссбраузерность вашего сайта
- 10. FUTURE REVISIONS OF THIS LICENSE
- How to use this License for your documents