Як отримати доступ до правильного "цього" всередині зворотного дзвінка?


1425

У мене функція конструктора, яка реєструє обробник подій:

function MyConstructor(data, transport) {
    this.data = data;
    transport.on('data', function () {
        alert(this.data);
    });
}

// Mock transport object
var transport = {
    on: function(event, callback) {
        setTimeout(callback, 1000);
    }
};

// called as
var obj = new MyConstructor('foo', transport);

Однак я не в змозі отримати доступ до dataвластивості створеного об'єкта всередині зворотного дзвінка. Схоже, thisце стосується не створеного об'єкту, а іншого.

Я також намагався використовувати метод об'єкта замість анонімної функції:

function MyConstructor(data, transport) {
    this.data = data;
    transport.on('data', this.alert);
}

MyConstructor.prototype.alert = function() {
    alert(this.name);
};

але це проявляє ті самі проблеми.

Як я можу отримати доступ до правильного об’єкта?


95
Час від часу я так набрид певним питанням, що вирішу написати канонічну відповідь. Незважаючи на те, що на ці запитання відповіли мільйон разів, не завжди вдається знайти хорошу пару + відповіді, яка не "забруднена" нерелевантною інформацією. Це один із цих моментів і одне з цих питань (і мені нудно). Якщо ви думаєте, що насправді існує хороший канонічний питання / відповідь на цей тип запитань, дайте мені знати, і я видалю це. Пропозиції щодо вдосконалень вітаються!
Фелікс Клінг



3
Про це корисна сторінка TypeScript , в основному застосовна і для JS.
Ondra Žižka

Відповіді:


1790

Про що слід знати this

this(він же "контекст") - це спеціальне ключове слово всередині кожної функції, і його значення залежить лише від того, як функція викликалася, а не як / коли / де вона була визначена. На неї не впливають лексичні області, як і інші змінні (крім функцій стрілок, див. Нижче). Ось кілька прикладів:

function foo() {
    console.log(this);
}

// normal function call
foo(); // `this` will refer to `window`

// as object method
var obj = {bar: foo};
obj.bar(); // `this` will refer to `obj`

// as constructor function
new foo(); // `this` will refer to an object that inherits from `foo.prototype`

Щоб дізнатися більше про thisце, ознайомтеся з документацією MDN .


Як посилатися на правильне this

Не використовуйте this

Ви фактично не хочете отримати доступ thisзокрема, але об’єкт, на який він посилається . Ось чому легким рішенням є просто створити нову змінну, яка також посилається на цей об’єкт. Змінна може мати будь-яке ім'я, але поширеними є selfі that.

function MyConstructor(data, transport) {
    this.data = data;
    var self = this;
    transport.on('data', function() {
        alert(self.data);
    });
}

Оскільки selfце звичайна змінна, вона підпорядковується лексичним правилам області застосування та є доступною всередині зворотного дзвінка. Це також має перевагу в тому, що ви можете отримати доступ до thisзначення самого зворотного дзвінка.

Явно встановлений thisзворотний дзвінок - частина 1

Це може здатися, що ви не маєте контролю над значенням, thisоскільки його значення встановлюється автоматично, але це насправді не так.

Кожна функція має метод .bind [docs] , який повертає нову функцію з thisприв’язкою до значення. Функція має точно таку саму поведінку, як та, яку ви викликали .bind, лише та, thisяку ви встановили. Незалежно від того, як або коли ця функція викликається, thisзавжди буде посилатися на передане значення.

function MyConstructor(data, transport) {
    this.data = data;
    var boundFunction = (function() { // parenthesis are not necessary
        alert(this.data);             // but might improve readability
    }).bind(this); // <- here we are calling `.bind()` 
    transport.on('data', boundFunction);
}

У цьому випадку ми прив'язуємо зворотний виклик thisдо значення MyConstructors this.

Примітка: Прив'язуючи контекст для jQuery, використовуйте замість нього jQuery.proxy [docs] . Причиною цього є те, що вам не потрібно зберігати посилання на функцію під час від'єднання зворотного виклику події. jQuery обробляє це внутрішньо.

ECMAScript 6: Використовуйте функції стрілок

ECMAScript 6 представляє функції стрілок , які можна розглядати як лямбда-функції. Вони не мають власної thisприв'язки. Натомість thisшукається в області застосування, як звичайна змінна. Це означає, що вам не потрібно дзвонити .bind. Це не єдина особлива поведінка у них, будь ласка, зверніться до документації MDN для отримання додаткової інформації.

function MyConstructor(data, transport) {
    this.data = data;
    transport.on('data', () => alert(this.data));
}

Набір thisзворотного дзвінка - частина 2

Деякі функції / методи, які приймають зворотні дзвінки, також приймають значення, до якого thisслід звернутися. Це в основному те саме, що зв’язувати його самостійно, але функція / метод робить це за вас. Array#map [docs] - такий метод. Його підпис:

array.map(callback[, thisArg])

Перший аргумент - це зворотний виклик, а другий аргумент - значення, на яке thisслід посилатися. Ось надуманий приклад:

var arr = [1, 2, 3];
var obj = {multiplier: 42};

var new_arr = arr.map(function(v) {
    return v * this.multiplier;
}, obj); // <- here we are passing `obj` as second argument

Примітка: Якщо ви можете передавати значення thisчи ні, зазвичай згадується в документації цієї функції / методу. Наприклад, метод jQuery [docs]$.ajax описує параметр, який називається context:

Цей об'єкт стане контекстом усіх зворотних викликів, пов'язаних з Ajax.


Поширена проблема: використання об'єктних методів як зворотних дзвінків / обробників подій

Іншим поширеним проявом цієї проблеми є те, коли метод об'єкта використовується як обробник викликів / подій. Функції є громадянами першого класу в JavaScript, а термін "метод" - це просто розмовний термін для функції, яка є значенням властивості об'єкта. Але ця функція не має конкретного посилання на об'єкт, що "містить".

Розглянемо наступний приклад:

function Foo() {
    this.data = 42,
    document.body.onclick = this.method;
}

Foo.prototype.method = function() {
    console.log(this.data);
};

Функція this.methodпризначається як обробник подій клацання, але якщо document.bodyнатиснуто на, значення буде зареєстровано undefined, оскільки всередині обробника подій thisвідноситься до document.body, а не до екземпляра Foo.
Як вже було сказано на початку, те, що thisстосується, залежить від того, як функція викликається , а не як вона визначається .
Якщо код виглядав наступним чином, може бути більш очевидним, що функція не має неявного посилання на об'єкт:

function method() {
    console.log(this.data);
}


function Foo() {
    this.data = 42,
    document.body.onclick = this.method;
}

Foo.prototype.method = method;

Рішення таке ж, як згадувалося вище: Якщо доступно, використовуйте .bindдля явного прив’язки thisдо конкретного значення

document.body.onclick = this.method.bind(this);

або явно викликати функцію як "метод" об'єкта, використовуючи анонімну функцію як обробник виклику / події та призначити об'єкт ( this) іншій змінній:

var self = this;
document.body.onclick = function() {
    self.method();
};

або скористайтеся функцією стрілки:

document.body.onclick = () => this.method();

39
Фелікс, я раніше читав цю відповідь, але ніколи не відповів. Я переживаю, що люди використовують selfі thatзвертаються до них this. Я відчуваю це так, тому що thisце перевантажена змінна, що використовується в різних контекстах; тоді як selfзазвичай відповідає локальному екземпляру і thatзазвичай посилається на інший об'єкт. Я знаю, що ви не встановили це правило, як я бачив, як воно з’являється в ряді інших місць, але це також, чому я почав використовувати _this, але не впевнений, як почуваються інші, за винятком нерівномірної практики що призвело.
vol7ron

3
@FelixKling можна було б припустити, що використання цієї функції прототипу завжди матиме очікувану поведінку незалежно від того, як вони (як правило) називаються? Використовуючи зворотні виклики всередині функцій прототипу, чи існує альтернатива bind (), self чи that?
andig

5
@FelixKling Це може бути корисно іноді покладатися на Function.prototype.call ()і Function.prototype.apply (). Зокрема, apply ()я набрав багато пробігу. Я менш схильний використовувати, bind ()можливо, лише за звичкою, хоча я усвідомлюю (але не впевнений), що можуть бути незначні переваги щодо використання bind над іншими варіантами.
Ноло

5
Чудова відповідь, але розглянути можливість додавання додаткового необов'язкового рішення, яке полягає у тому, щоб просто не використовувати класи, нові чи це взагалі.
Алуан Хаддад

4
re arrow функцій "Натомість це шукається в області застосування, як звичайна змінна." повністю зробив цей клік для мене, дякую! () => this.clicked();)
буквено-цифровий0101

211

Ось кілька способів доступу до батьківського контексту в дочірнім контексті -

  1. Ви можете використовувати bind()функцію.
  2. Зберігати посилання на контекст / це всередині іншої змінної (див. Приклад нижче).
  3. Використовуйте функції стрілки ES6 .
  4. Змінення дизайну / архітектури коду / функції - для цього ви повинні мати команду над шаблонами дизайну в JavaScript.

1. Використовуйте bind()функцію

function MyConstructor(data, transport) {
    this.data = data;
    transport.on('data', ( function () {
        alert(this.data);
    }).bind(this) );
}
// Mock transport object
var transport = {
    on: function(event, callback) {
        setTimeout(callback, 1000);
    }
};
// called as
var obj = new MyConstructor('foo', transport);

Якщо ви використовуєте underscore.js- http://underscorejs.org/#bind

transport.on('data', _.bind(function () {
    alert(this.data);
}, this));

2 Зберігати посилання на контекст / це всередині іншої змінної

function MyConstructor(data, transport) {
  var self = this;
  this.data = data;
  transport.on('data', function() {
    alert(self.data);
  });
}

3 Функція стрілки

function MyConstructor(data, transport) {
  this.data = data;
  transport.on('data', () => {
    alert(this.data);
  });
}

1
Варіант bind () дивовижний тим, що просто передає вказівник цього Об'єкта, щоб бути цим на іншому об'єкті (: Спасибі!
Став Бодик

Бінд () працює як шарм. Дуже дякую +1 від мене :)
Аняна Сільва

56

Все це в "чарівному" синтаксисі виклику методу:

object.property();

Коли ви отримаєте властивість від об'єкта та зателефонуєте йому за один раз, об'єкт буде контекстом для методу. Якщо ви називаєте той самий метод, але окремими кроками, то контекст - це глобальна область (вікно):

var f = object.property;
f();

Коли ви отримуєте посилання на метод, він більше не приєднується до об'єкта, це лише посилання на звичайну функцію. Те саме відбувається, коли ви отримуєте посилання на використання в якості зворотного дзвінка:

this.saveNextLevelData(this.setAll);

Ось де ви прив’яжете контекст до функції:

this.saveNextLevelData(this.setAll.bind(this));

Якщо ви використовуєте jQuery, вам слід скористатися $.proxyметодом, bindякий підтримується не у всіх браузерах:

this.saveNextLevelData($.proxy(this.setAll, this));

33

Проблема з "контекстом"

Термін «контекст» іноді використовується для позначення об'єкта , на який посилається цей . Його використання є недоцільним, оскільки воно ні семантично, ні технічно не відповідає цьому ECMAScript .

"Контекст" означає обставини, що оточують щось, що додає сенсу, або якусь попередню та наступну інформацію, що надає додатковий сенс. Термін "контекст" використовується в ECMAScript для позначення контексту виконання , який є всіма параметрами, областю та цим в межах деякого виконуючого коду.

Це показано в розділі 10.4.2 ECMA-262 :

Встановіть ThisBinding на те саме значення, що і ThisBinding контексту виконання виклику

що чітко вказує, що це частина контексту виконання.

Контекст виконання забезпечує оточуючу інформацію, яка додає значення коду, який виконується. Вона включає в себе набагато більше інформації, ніж просто це Пов'язування .

Отже, значення цього не "контексту", це лише одна частина контексту виконання. По суті це локальна змінна, яку можна встановити викликом до будь-якого об'єкта і в суворому режимі, будь-якого значення взагалі.


Не можу погодитися з цією відповіддю. Наявність терміна "контекст виконання" не забороняє інших застосувань "контексту" більше, ніж це забороняє інші види використання "виконання". Можливо, є кращий термін для опису, thisале жоден тут не пропонується, і, мабуть, занадто пізно, щоб закрити двері на "контекст".
Роумер-1888

@ Roamer-1888 - дякую за редагування. Ви маєте рацію, але мій аргумент не покладається на існування "контексту виконання", що виключає "контекст" для якоїсь іншої мети. Швидше, це базується на тому, що "контекст" є недоречним як з технічної, так і з семантичної точки зору. Я також думаю, що використання "контексту" замість "цього" згасає. Я не бачу жодних причин знайти альтернативний термін цьому чи цьомуЗв'язуванню , він просто обдумує і означає, що в якийсь момент ви повинні пояснити, що "контекст" насправді це , і що це ні в якому разі не "контекст". :-)
RobG

Я не думаю, що ви можете сказати, що це жодним чином не "контекст", коли ви вже визнали, що це одна частина контексту виконання, де "виконання" є просто прикметником.
Роумер-1888,

@ Roamer-1888 - я не збираюся продовжувати цю розмову минулої точки. Так, це є частиною контексту виконання. Говорячи це контекст, як кажуть один гравець команди є командою.
RobG

RobG, шкода, що ти не хочеш продовжувати. Це цікава дискусія. Дякую, що ви приділили мені свій час.
Роумер-1888,

31

Вам слід знати про "це" ключове слово.

Як на мою думку, ви можете реалізувати "це" трьома способами (функція Self / Arrow / Метод прив'язки)

Функція цього ключового слова поводиться в JavaScript дещо інакше порівняно з іншими мовами.

Він також має деякі відмінності між суворим режимом і нестрогим режимом.

У більшості випадків значення цього визначається тим, як викликається функція.

Його не можна встановити за призначенням під час виконання, і він може бути різним щоразу, коли функція викликається.

ES5 представив метод bind () для встановлення значення функції це незалежно від того, як вона викликається,

і ES2015 запровадили функції зі стрілками, які не забезпечують власну цю прив'язку (вона зберігає це значення додається лексичного контексту).

Метод1: " Я - Я" використовується для підтримки посилання на оригінал, навіть коли контекст змінюється. Це техніка, яка часто використовується в обробниках подій (особливо при закритті).

Довідка : https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this

function MyConstructor(data, transport) {
    this.data = data;
    var self = this;
    transport.on('data', function () {
        alert(self.data);
    });
}

Метод2 : Функція стрілки - Вираз функції стрілки є синтаксично компактною альтернативою звичайному виразу функції,

хоча без власних прив’язків до цього, аргументів, супер або нових ключових слів.

Висловлення функції стрілки погано підходять як методи, і їх не можна використовувати як конструктори.

Довідка : https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions

  function MyConstructor(data, transport) {
    this.data = data;
    transport.on('data',()=> {
        alert(this.data);
    });
}

Метод 3 : Bind - Метод bind () створює нову функцію, яка,

коли дзвонить, його ключове слово встановлено на задане значення,

з заданою послідовністю аргументів, що передує будь-яким, наданим, коли викликається нова функція.

Довідка: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_objects/Function/bind

  function MyConstructor(data, transport) {
    this.data = data;
    transport.on('data',(function() {
        alert(this.data);
    }).bind(this);

25

По-перше, ви повинні мати чітке розуміння scopeта поведінку thisключового слова в контексті scope.

this& scope:


there are two types of scope in javascript. They are :

   1) Global Scope

   2) Function Scope

коротше кажучи, глобальна сфера стосується об'єкта вікна. Змінні, оголошені в глобальній області, доступні з будь-якого місця. З іншого боку, сфера функціонування розташована всередині функції. Змінний декларований всередині функції не може бути доступний із зовнішнього світу нормально. thisКлючове слово в глобальній області стосується об'єкта вікна. thisвнутрішня функція також відноситься до об'єкта вікна. Тому thisзавжди будемо посилатися на вікно, поки ми не знайдемо спосіб маніпулювати, thisщоб вказати на контекст власного вибору.

--------------------------------------------------------------------------------
-                                                                              -
-   Global Scope                                                               -
-   ( globally "this" refers to window object)                                 -     
-                                                                              -
-         function outer_function(callback){                                   -
-                                                                              -
-               // outer function scope                                        -
-               // inside outer function"this" keyword refers to window object -                                                                              -
-              callback() // "this" inside callback also refers window object  -

-         }                                                                    -
-                                                                              -
-         function callback_function(){                                        -
-                                                                              -
-                //  function to be passed as callback                         -
-                                                                              -
-                // here "THIS" refers to window object also                   -
-                                                                              -
-         }                                                                    -
-                                                                              -
-         outer_function(callback_function)                                    -
-         // invoke with callback                                              -
--------------------------------------------------------------------------------

Різні способи маніпулювання thisфункціями зворотного виклику:

Тут у мене функція конструктора під назвою Person. Він має властивість nameі чотири методи , званого sayNameVersion1, sayNameVersion2, sayNameVersion3, sayNameVersion4. Усі чотири з них мають одне конкретне завдання. Прийміть зворотний виклик і викликайте його. Зворотний виклик має конкретне завдання, яке полягає в реєстрації властивості імені екземпляра функції конструктора Person.

function Person(name){

    this.name = name

    this.sayNameVersion1 = function(callback){
        callback.bind(this)()
    }
    this.sayNameVersion2 = function(callback){
        callback()
    }

    this.sayNameVersion3 = function(callback){
        callback.call(this)
    }

    this.sayNameVersion4 = function(callback){
        callback.apply(this)
    }

}

function niceCallback(){

    // function to be used as callback

    var parentObject = this

    console.log(parentObject)

}

Тепер давайте створимо екземпляр з конструктора персони та застосуємо різні версії методу sayNameVersionX(X посилається на 1,2,3,4), niceCallbackщоб побачити, якими способами ми можемо маніпулювати thisвнутрішнім зворотним викликом для посилання на personекземпляр.

var p1 = new Person('zami') // create an instance of Person constructor

прив’язувати:

Що потрібно зробити, це створити нову функцію з thisключовим словом, встановленим на задане значення.

sayNameVersion1і sayNameVersion2використовувати прив'язку для маніпулювання thisфункцією зворотного дзвінка.

this.sayNameVersion1 = function(callback){
    callback.bind(this)()
}
this.sayNameVersion2 = function(callback){
    callback()
}

Перший прив'язується thisіз зворотним дзвоном всередині самого методу. А для другого передається зворотний виклик із прив'язаним до нього об'єктом.

p1.sayNameVersion1(niceCallback) // pass simply the callback and bind happens inside the sayNameVersion1 method

p1.sayNameVersion2(niceCallback.bind(p1)) // uses bind before passing callback

дзвінок:

first argumentВід callметоду використовується як thisвсередині функції , яка викликається з callдодається до нього.

sayNameVersion3використовує callдля маніпулювання thisпозначення об'єкта людини, який ми створили, а не об'єкт вікна.

this.sayNameVersion3 = function(callback){
    callback.call(this)
}

і називається так:

p1.sayNameVersion3(niceCallback)

застосувати:

Аналогічно call, перший аргумент applyпосилається на об'єкт, який буде вказаний thisключовим словом.

sayNameVersion4використовує applyдля маніпулювання thisдля позначення людини об'єкта

this.sayNameVersion4 = function(callback){
    callback.apply(this)
}

і він називається наступним чином. Просто повернення виклику передано,

p1.sayNameVersion4(niceCallback)

1
будь-яка конструктивна критика стосовно відповіді буде оцінена!
AL-zami

1
Це ключове слово в глобальній області не обов’язково стосується об'єкта вікна . Це вірно лише в браузері.
Рандалл Флагг

1
@RandallFlagg я написав цю відповідь з точки зору веб-переглядача. Не забувайте, якщо це необхідно, відповісти на цю відповідь :)
AL-zami

19

Ми не можемо пов'язувати це setTimeout(), як це завжди виконується з глобальним об'єктом (Window) , якщо ви хочете отримати доступ до thisконтексту у функції зворотного виклику, використовуючи bind()функцію зворотного виклику, ми можемо досягти як:

setTimeout(function(){
    this.methodName();
}.bind(this), 2000);

9
Чим це відрізняється від будь-яких існуючих відповідей?
Фелікс Клінг

13

Питання обертається тим, як thisключове слово поводиться в JavaScript. thisповодиться інакше, як нижче,

  1. Значення this зазвичай визначається контекстом виконання функцій.
  2. У глобальному масштабі thisвідноситься до глобального об'єкта ( windowоб'єкта).
  3. Якщо ввімкнено суворий режим для будь-якої функції, то значення vol thisбуде таким, undefinedяк у суворому режимі, undefinedзамість об'єкта посилається глобальний windowоб'єкт.
  4. Об'єкт, який стоїть перед крапкою, - це те, до чого буде пов'язане це ключове слово.
  5. Ми можемо встановити значення цього явно з call(), bind()іapply()
  6. Коли використовується newключове слово (конструктор), воно пов'язане з новим об'єктом, який створюється.
  7. Функції стрілки не пов'язуються this - натомість thisпов'язані лексично (тобто на основі вихідного контексту)

Як підказує більшість відповідей, ми можемо використовувати функцію стрілки або bind()метод або самоврядування . Я б процитував пункт про лямбда (функція стрілки) з посібника зі стилю Google JavaScript

Переважно використовувати функції стрілок над f.bind (це), а особливо над goog.bind (f, this). Уникайте написання const self = this. Функції стрілки особливо корисні для зворотних викликів, які іноді передають несподівані додаткові аргументи.

Google чітко рекомендує використовувати лямбда, а не зв'язувати або const self = this

Тож найкращим рішенням буде використання лямбдаш, як показано нижче,

function MyConstructor(data, transport) {
  this.data = data;
  transport.on('data', () => {
    alert(this.data);
  });
}

Список літератури:

  1. https://medium.com/tech-tajawal/javascript-this-4-rules-7354abdb274c
  2. стрілки-функції vs-bind

Це питання стосується використання функцій / методів як зворотних дзвінків. Ваша відповідь може бути краще підходить для stackoverflow.com/q/3127429/218196 .
Фелікс Клінг

@FelixKling Так, питання про використання функцій / методів як зворотних викликів у цій головній проблемі було пов'язано з обробкою thisключового слова, тому я розділив свою відповідь на дві частини, одну про thisта другу про використання функцій / методів як зворотних викликів. Сміливо редагуйте відповідь.
Code_Mode

Я вважаю ваш четвертий пункт викладеним неоднозначно. Розглянемо приклад “Проблема при використанні методів із цим об’єктом як зворотній зв'язок” , де правий об’єкт стоїть перед крапкою, але контекст все ще не є цим об’єктом.
bleistift2

7

В даний час можливий інший підхід, якщо класи використовуються в коді.

З підтримкою класових полів це можливо зробити наступним чином:

class someView {
    onSomeInputKeyUp = (event) => {
        console.log(this); // this refers to correct value
    // ....
    someInitMethod() {
        //...
        someInput.addEventListener('input', this.onSomeInputKeyUp)

Напевно, під кришкою - це все стара функція гарної стрілки, яка пов'язує контекст, але в такому вигляді виглядає набагато чіткіше, що явне прив'язування.

Оскільки це пропозиція на етапі 3, для обробки цього вам знадобиться джемпер та відповідний плагін (08/2018).


2
Саме так я і отримав це, працюючи в Typescript: public methodName = (params) => { body }всередині класу.
yeyeyerman

5

Інший підхід, який є стандартним способом прив'язки DOM2 до thisслухача події, що дозволяє вам завжди видаляти слухача (серед інших переваг), - це handleEvent(evt)метод з EventListenerінтерфейсу:

var obj = {
  handleEvent(e) {
    // always true
    console.log(this === obj);
  }
};

document.body.addEventListener('click', obj);

Детальну інформацію про використання handleEventможна знайти тут: https://medium.com/@WebReflection/dom-handleevent-a-cross-platform-standard-since-year-2000-5bf17287fd38


0

this в JS:

Значення thisJS на 100% визначається тим, як викликається функція, а не як вона визначається. Ми можемо досить легко знайти значення thisсамих «зліва від правила точкової» :

  1. Коли функція створена за допомогою ключового слова функції, значення this- це об'єкт, зліва від точки функції, яка викликається
  2. Якщо від точки немає лівого об'єкта, значенням thisвнутрішньої функції часто є глобальний об'єкт ( globalу вузлі, windowу браузері). Я б не рекомендував використовувати thisтут ключове слово, оскільки воно менш явне, ніж використання чогось подібного window!
  3. Існують певні конструкції, такі як функції стрілок та функції, створені за допомогою Function.prototype.bind()функції, яка може фіксувати значення this. Це винятки з правила, але вони справді корисні для встановлення значення this.

Приклад у nodeJS

module.exports.data = 'module data';
// This outside a function in node refers to module.exports object
console.log(this);

const obj1 = {
    data: "obj1 data",
    met1: function () {
        console.log(this.data);
    },
    met2: () => {
        console.log(this.data);
    },
};

const obj2 = {
    data: "obj2 data",
    test1: function () {
        console.log(this.data);
    },
    test2: function () {
        console.log(this.data);
    }.bind(obj1),
    test3: obj1.met1,
    test4: obj1.met2,
};

obj2.test1();
obj2.test2();
obj2.test3();
obj2.test4();
obj1.met1.call(obj2);

Вихід:

введіть тут опис зображення

Дозвольте мені провести вас через результати 1 на 1 (ігноруючи перший журнал, починаючи з другого):

  1. thisце obj2з - за ліву частину правила точки, ми можемо бачити , як test1називаються obj2.test1();. obj2ліворуч від крапки і, отже, значкаthis значення.
  2. Навіть незважаючи на те obj2, що залишилася від точки, test2це пов'язано obj1з bind()методом. Значить thisцінність є obj1.
  3. obj2знаходиться зліва від точки з функції , яка називається: obj2.test3(). Тому obj2буде значенняthis .
  4. У цьому випадку: obj2.test4() obj2ліворуч від крапки. Однак функції стрілки не мають власного thisприв’язки. Тому він буде прив'язуватися до thisзначення зовнішньої області, яка єmodule.exports об'єктом, який був зареєстрований на початку.
  5. Ми також можемо вказати значення this, використовуючи callфункцію. Тут ми можемо передати бажане thisзначення як аргумент, що є obj2в даному випадку.
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.