Глобальное это
Вне функции this
ссылается на глобальный объект. В среде браузера это обычно окно объекта. В этом сценарии вы можете установить свойства глобального объекта, сославшись на него следующим образом:
this.name = 'Kudzanayi'; console.log(window.name); // Kudzanayi console.log(name); // Kudzanayi console.log(this.name); // Kudzanayi
это внутри функции, вызываемой на объекте
Предположим, у нас есть следующий объект:
const kudzanayi = { name: 'Kudzanayi', sayHello() { console.log(`Hello, I'm ${this.name}` } }
Если мы вызовем функцию sayHello для объекта kudzanayi следующим образом:
joe.sayHello(); //prints 'Hello, I'm Joe'
Тогда this
внутри функции sayHello
ссылается на объект kudzanayi
.
Когда вы вызываете функцию для объекта, используя запись через точку, как мы делали выше, вы можете сказать, что this
относится к объекту перед точкой. Иногда его называют приемником.
Однако если мы сохраним ссылку на функцию sayHello
и вызовем ее через ссылку, мы получим другой результат:
const greet = joe.sayHello; greet() //prints "Hello, I'm undefined"
Когда в вызове функции нет явного получателя, this
относится к глобальному объекту. Если ничто другое не установило свойство name
для оконного объекта, это напечатает Hello, I'm undefined
Если какой-то другой код установил свойство имени для объекта окна, он напечатает его вместо этого. Рассмотрим следующий код:
name = 'Rutendo' const kudzanayi = { name: ' Kudzanayi', sayHello() { console.log(`Hello, I'm ${this.name}) } } kudzanayi.sayHello();// prints "Hello, I'm kudzanayi" const greet = kudzanayi.sayHello greet()// "Hello, I'm Rutendo" const farai = { name: 'Farai' sayHello: kudzanayi.sayHello } farai.sayHello();// 'Hello, I'm Farai'
this
внутри прослушивателя событий
Другим распространенным сценарием является прослушиватель событий. При добавлении прослушивателя событий указывается функция обратного вызова для обработки события. Когда вызывается этот обратный вызов, это относится к объекту, к которому был добавлен прослушиватель событий.
document.querySelector('button.myButton').addEventListener('click', function(){ this.style.background = 'red'})
Здесь мы добавили прослушиватель кликов к кнопке. Когда кнопка нажата и функция обратного вызова выполняется, this
относится к кнопке.
это внутри обратного вызова
В Array.prototype есть несколько полезных функций, таких как forEach, map, reduce
Каждая из них принимает функцию обратного вызова в качестве аргумента.
Внутри обратного вызова, переданного этим функциям, this
снова ссылается на глобальный объект.
const arr = [1,2,3] arr.forEach(function(item){ console.log(this) })
Когда приведенный выше код запускается в браузере, он трижды выводит объект window
на консоль.
Рассмотрим следующий код
name = 'rutendo' const kudzanayi = { name: 'kudzanayi' greet(people){ people.forEach(function(person){ console.log(`Hello ${person}, I'm ${this.name}`) }) } } kudzanayi.greet(['farai', 'oswald'])
Следующее будет производить
Hello farai, I'm rutendo Hello oswald, I'm rutendo
Несмотря на то, что функция greet
имеет значение this
объекта kudzanayi, внутри обратного вызова к forEach
значением this.name
является Боб, который был установлен для объекта window
.
Как нам изменить код, чтобы он печатал кудзанайи вместо рутэндо
Один из способов — изменить ссылку на this
и указать ее внутри обратного вызова:
name = 'rutendo' const kudzanayi = { name: 'kudzanayi' greet(people){ const self = this people.forEach(function(person){ console.log(`Hello ${person}, I'm ${this.name}`) }) } } kudzanayi.greet(['farai', 'oswald'])
Получаем желаемый результат
Hello farai, I'm kudzanayi Hello oswald, I'm kudzanayi
Почему умирает эта работа? Поскольку функция наследует окружающую область (спасибо, закрытие), значение self
можно получить из функции обратного вызова.
Но есть лучшие способы сделать это
Изменение значения этого
используя функцию стрелки
Самый простой способ выполнить то, что делает предыдущий пример кода, — использовать функцию стрелки вместо синтаксиса function() {...}
.
Стрелочная функция не получает своего собственного this
, а наследует this
своей области видимости. Мы можем переписать предыдущий пример, используя стрелочные функции:
name = 'rutendo' const kudzanayi = { name: 'kudzanayi' greet(people){ people.forEach(person => console.log(`Hello ${person}, I'm ${this.name}`)) } } kudzanayi.greet(['farai', 'oswald'])
вывод такой же как и раньше
Hello farai, I'm kudzanayi Hello oswald, I'm kudzanayi
Значение this
внутри обратного вызова стрелки — это объект kudzanayi
.
Используйте Function.prototype.bind
В прототипе Function.
есть несколько удобных функций. Одна из них — bind. С помощью этой функции вы можете изменить то, на что ссылается this
в функции.
const kudzanayi = { name: 'kudzanayi' sayHello(){ console.log(`Hello, I'm ${this.name}`) } } const greet = kudzanayi.sayHello; greet();
Мы уже знаем, что код напечатает undefined
вместо kudzanayi
. Однако мы можем исправить это, вызвав bind
const kudzanayi = { name: 'kudzanayi' sayHello(){ console.log(`Hello, I'm ${this.name}`) } } const greet = kudzanayi.sayHello.bind(kudzanayi) greet() // prints 'Hello, I'm Kudzanayi'
Вот что делает bind: Вызов bind
для функции, как мы сделали выше, возвращает новую функцию, значение this
которой привязано к первому аргументу, переданному в bind
.
kudzanayi.sayHello
— это ссылка на функцию sayHello
. Мы вызываем bind(kudzanayi) для этой функции, которая возвращает новую функцию, в которой this
привязан к объекту joe. Так что код работает как задумано.
Используйте Function.prototype.call или function.prototype, примените
Две другие полезные функции прототипа Function
— это call
и apply
. У них обоих один и тот же результат, просто они подходят к нему немного по-разному, как мы сейчас увидим.
const kudzanayi = { name: 'kudzanayi' greet(person){ console.log(`Hello ${person}, I'm ${this.name}`) } } const greet = kudzanayi.greet; greet('rutendo'); // Hello rutendo, I'm undefined greet.call(kudzanayi, 'rutendo) // Hello rutendo, I'm kudzanyi greet.apply(kudzanayi, ['rutendo'])// Hello rutendo, I'm kudzanayi
call
и apply
оба выполняют одни и те же цели, но есть небольшая разница в том, как они используются.
Оба они вызывают функцию с первым аргументом, привязанным к значению this
.
Это похоже на bind
, как мы делали выше, но с одним ключевым отличием. Bind возвращает новую функцию, которая всегда будет иметь указанное значение this
для вызова. call
и apply
работают с исходной функцией, и их эффекты применяются только к этому единственному вызову.
Разница между ними заключается в том, как мы указываем аргументы для вызовов функций. call
принимает переменное количество аргументов, а apply
принимает аргументы в виде массива.