JavaScript this
Просте виклик функції
Розглянемо наступну функцію:
function foo() {
console.log("bar");
console.log(this);
}
foo(); // calling the function
Зауважте, що ми виконуємо це у звичайному режимі, тобто суворий режим не використовується.
Під час запуску в браузері значення " thisзаписується як" window. Це тому, що windowє глобальною змінною в області веб-браузера.
Якщо ви запускаєте цей самий фрагмент коду в середовищі, як node.js, thisбуде посилатися на глобальну змінну у вашому додатку.
Тепер, якщо ми запустимо це в суворому режимі, додавши оператор "use strict";на початок декларації функції, thisбільше не буде посилатися на глобальну змінну в жодному з середовищ. Це робиться для уникнення плутанини в суворому режимі. thisв цьому випадку просто журнал undefined, тому що це є, він не визначений.
У наступних випадках ми побачимо, як маніпулювати значенням this.
Виклик функції на об'єкті
Існують різні способи зробити це. Якщо ви назвали нативні методи в JavaScript як, forEachі sliceви вже повинні знати, що thisзмінна в цьому випадку відноситься до того, Objectна яке ви викликали цю функцію (зауважте, що в javascript майже все є Object, включаючи Arrays і Functions). Візьмемо для прикладу наступний код.
var myObj = {key: "Obj"};
myObj.logThis = function () {
// I am a method
console.log(this);
}
myObj.logThis(); // myObj is logged
Якщо вміст Objectмістить властивість, яка містить а Function, властивість називається методом. Цей метод, коли його викликають, завжди матиме thisзмінну, встановлену наObject він пов'язаний. Це справедливо як для суворих, так і не суворих режимів.
Зауважте, що якщо метод зберігається (вірніше, скопіюється) в іншій змінній, посилання на thisбільше не зберігається в новій змінній. Наприклад:
// continuing with the previous code snippet
var myVar = myObj.logThis;
myVar();
// logs either of window/global/undefined based on mode of operation
Розглядаючи більш практичний сценарій:
var el = document.getElementById('idOfEl');
el.addEventListener('click', function() { console.log(this) });
// the function called by addEventListener contains this as the reference to the element
// so clicking on our element would log that element itself
newключове слово
Розглянемо функцію конструктора в Javascript:
function Person (name) {
this.name = name;
this.sayHello = function () {
console.log ("Hello", this);
}
}
var awal = new Person("Awal");
awal.sayHello();
// In `awal.sayHello`, `this` contains the reference to the variable `awal`
Як це працює? Що ж, давайте подивимося, що станеться, коли ми використовуємо newключове слово.
- Виклик функції за допомогою
newключового слова негайно ініціалізує ObjectтипPerson .
- Конструктор цього
Objectмає свій конструктор Person. Також зверніть увагу, що typeof awalповернетьсяObject лише.
- Цьому новому
Objectбуде призначений прототип Person.prototype. Це означає, що будь-який метод чи властивість у Personпрототипі будуть доступні для всіх примірників Person, у тому числіawal .
- Тепер функція
Personвикликається; thisбудучи посиланням на щойно побудований об’єкт awal.
Досить прямо, так?
Зауважте, що в офіційній специфікації ECMAScript ніде не зазначено, що такі типи функцій є фактичними constructorфункціями. Вони просто нормальні функції, і newїх можна використовувати на будь-якій функції. Просто ми використовуємо їх як таких, і тому називаємо їх лише такими.
Виклик функцій у функціях: callіapply
Так, так як functions також є Objects(і фактично змінні першого класу в Javascript), навіть функції мають методи, які ... ну, самі функції.
Всі функції успадковуються від глобального Function, і два з його багатьох методів є callі apply, і обидва можуть бути використані для маніпулювання значенням thisфункції, за якою вони викликаються.
function foo () { console.log (this, arguments); }
var thisArg = {myObj: "is cool"};
foo.call(thisArg, 1, 2, 3);
Це типовий приклад використання call. В основному він приймає перший параметр і задає thisфункцію fooяк посилання на thisArg. Усі інші параметри, передані до call, передаються функції fooяк аргументи.
Тож вищевказаний код увійде {myObj: "is cool"}, [1, 2, 3]в консоль. Досить приємний спосіб змінити значенняthis будь-якої функції.
applyмайже такий же, як callприйняти, що він приймає лише два параметри: thisArgі масив, який містить аргументи, які потрібно передавати функції. Отже, вищезгаданий callвиклик можна перекласти applyтак:
foo.apply(thisArg, [1,2,3])
Зауважте, що callі applyможе перекрити значенняthis заданого викликом методу крапок, про який ми говорили у другій кулі. Досить просто :)
Представляючи…. bind !
bindє братом callі apply. Це також метод, успадкований усіма функціями від глобального Functionконструктора в Javascript. Різниця між bindі call/ applyполягає в тому, що і те, callі applyфактично буде викликати функцію. bind, З іншого боку, повертає нову функцію з thisArgі argumentsзаздалегідь заданими параметрами. Візьмемо приклад, щоб краще зрозуміти це:
function foo (a, b) {
console.log (this, arguments);
}
var thisArg = {myObj: "even more cool now"};
var bound = foo.bind(thisArg, 1, 2);
console.log (typeof bound); // logs `function`
console.log (bound);
/* logs `function () { native code }` */
bound(); // calling the function returned by `.bind`
// logs `{myObj: "even more cool now"}, [1, 2]`
Бачите різницю між трьома? Це тонко, але вони використовуються по-різному. Як callі apply, bindтакож буде перевищувати вартістьthis задане викликом методу крапок.
Також зауважте, що жодна з цих трьох функцій не змінює вихідну функцію. callі applyповертав би значення зі свіжозбудованих функційbind поверне саму щойно побудовану функцію, готову до виклику.
Зайві речі, скопіюйте це
Іноді вам не подобається той факт, що thisзмінюється в області застосування, особливо вкладеної області. Погляньте на наступний приклад.
var myObj = {
hello: function () {
return "world"
},
myMethod: function () {
// copy this, variable names are case-sensitive
var that = this;
// callbacks ftw \o/
foo.bar("args", function () {
// I want to call `hello` here
this.hello(); // error
// but `this` references to `foo` damn!
// oh wait we have a backup \o/
that.hello(); // "world"
});
}
};
У наведеному вище коді ми бачимо, що значення thisзмінилося з вкладеною областю, але ми хотіли, щоб значення було thisвід вихідної області. Таким чином , ми «скопійовано» thisв thatі використовується замість копіюванняthis . Розумний, так?
Індекс:
- Що тримається в
this за замовчуванням?
- Що робити, якщо ми називаємо функцію методом із нотацією Object-dot?
- Що робити, якщо ми використовуємо
new ключове слово?
- Як ми маніпулюємо
thisз callі apply?
- Використання
bind.
- Копіювання
thisдля вирішення вкладених проблем.