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
, включаючи Array
s і Function
s). Візьмемо для прикладу наступний код.
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
Так, так як function
s також є 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
для вирішення вкладених проблем.