Как получить доступ к правильному `this` внутри обратного вызова?

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.
Ондра Жижка

Ответы:

1791

Что вы должны знать о 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к значению MyConstructorх гг 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 [Документы] такой метод. Его подпись:

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 или что?
andig
5
@FelixKling Иногда бывает полезно положиться Function.prototype.call ()и на Function.prototype.apply (). Особенно с apply ()я получил много пробега. Я менее склонен использовать, bind ()возможно, только по привычке, хотя я знаю (но не уверен), что могут быть небольшие накладные преимущества при использовании привязки по сравнению с другими вариантами.
Ноло
5
Отличный ответ, но подумайте о добавлении дополнительного необязательного решения, которое состоит в том, чтобы просто не использовать классы, новые или это вообще.
Алуан Хаддад
4
re arrow functions "Вместо этого это выглядит в области видимости как обычная переменная." полностью сделал этот клик для меня, спасибо! () => this.clicked();)
alphanumeric0101
211

Вот несколько способов получить доступ к родительскому контексту внутри дочернего контекста:

  1. Вы можете использовать bind()функцию.
  2. Сохраните ссылку на context / this внутри другой переменной (см. Пример ниже).
  3. Используйте функции ES6 Arrow .
  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 Сохраните ссылку на context / this внутри другой переменной

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 () удивительна, просто передав указатель этого объекта, чтобы быть this на другом объекте (: Спасибо!
Став Бодик,
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));
Guffa
источник
33

Беда с "контекстом"

Термин «контекст» иногда используется для обозначения объекта, на который ссылается это . Его использование является неуместным , поскольку он не соответствует ни семантически , ни технически с ECMAScript - х это .

«Контекст» означает обстоятельства, окружающие что-то, что добавляет значение, или некоторую предшествующую и следующую информацию, которая придает дополнительный смысл. Термин «контекст» используется в ECMAScript для обозначения контекста исполнения , который представляет собой все параметры, область действия и это в рамках некоторого исполняемого кода.

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

Установите для ThisBinding то же значение, что и для ThisBinding вызывающего контекста выполнения.

который ясно указывает на то, что это является частью контекста исполнения.

Контекст выполнения предоставляет окружающую информацию, которая добавляет смысл к исполняемому коду. Он включает в себя гораздо больше информации, чем просто thisBinding .

Таким образом, значение этого не «контекст», это просто одна часть контекста исполнения. По сути, это локальная переменная, которая может быть установлена ​​при вызове любого объекта и в строгом режиме для любого значения вообще.

RobG
источник
Не могу согласиться с этим ответом. Существование термина «контекст исполнения» не запрещает иное использование «контекста», как и запрещает другое использование «исполнения». Возможно, есть лучший термин для описания, thisно здесь он не предлагается, и, возможно, уже слишком поздно закрывать дверь для «контекста».
Roamer-1888
@ Roamer-1888 - спасибо за редактирование. Вы правы, но мой аргумент не основан на существовании «контекста исполнения», исключающего «контекст» для какой-то другой цели. Скорее, это основано на том, что «контекст» неуместен как с технической, так и с семантической точки зрения. Я также думаю, что использование «контекста» вместо «этого» вымирает. Я не вижу причин, чтобы найти альтернативный термин для того или иного связывания , оно просто запутывает и означает, что в какой-то момент вам нужно объяснить, что «контекст» - это на самом деле , и что он в любом случае не «контекст». :-)
RobG
Я не думаю, что вы можете сказать, что это никоим образом не является «контекстом», когда вы уже признали, что это одна часть контекста выполнения, где «выполнение» просто прилагательное.
Roamer-1888
@ Roamer-1888 - я не собираюсь продолжать этот разговор до этого момента. Да, это является частью контекста исполнения. Говоря это контекст, как говорят один игрок команды является командой.
RobG
РобГ, жаль, что ты не хочешь продолжать. Это интересная дискуссия. Спасибо, что уделили мне время.
Roamer-1888
31

Вы должны знать об этом ключевом слове.

На мой взгляд, вы можете реализовать «это» тремя способами (Self / Arrow function / Bind Method)

Ключевое слово this функции ведет себя немного иначе в JavaScript по сравнению с другими языками.

Он также имеет некоторые различия между строгим режимом и не строгим режимом.

В большинстве случаев значение этого определяется тем, как вызывается функция.

Он не может быть установлен присваиванием во время выполнения и может отличаться при каждом вызове функции.

ES5 представил метод bind () для установки значения функции this независимо от того, как она вызывается,

и ES2015 представили функции стрелок, которые не обеспечивают собственную привязку this (она сохраняет значение this лексического контекста).

Метод 1: Self - Self используется для сохранения ссылки на оригинал, даже если контекст меняется. Эта техника часто используется в обработчиках событий (особенно в замыканиях).

Ссылка : 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 : функция стрелки - выражение функции стрелки является синтаксически компактной альтернативой регулярному выражению функции,

хотя без привязок к ключевым словам this, arguments, super или new.target.

Выражения функций стрелок плохо подходят в качестве методов, и их нельзя использовать в качестве конструкторов.

Ссылка : 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 () создает новую функцию, которая,

при вызове имеет ключевое слово this установленное значение,

с заданной последовательностью аргументов, предшествующей любому, предоставленному при вызове новой функции.

Ссылка: 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);
Ashish
источник
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. У всех четырех из них есть одна конкретная задача. Принять обратный вызов и вызвать его. Обратный вызов имеет специальную задачу, которая заключается в регистрации свойства name экземпляра функции конструктора 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)

}

Теперь давайте создадим экземпляр из конструктора person и вызовем разные версии метода 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ссылкой на объект person, который мы создали, вместо объекта window.

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)
AL-З
источник
1
любая конструктивная критика в отношении ответа будет оценена!
AL-zami
1
Ключевое слово this в глобальной области видимости не обязательно ссылается на объект окна . Это верно только в браузере.
Рэндалл Флэгг
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. Если строгий режим включен для любой функции, то значение thisбудет таким же, undefinedкак в строгом режиме, глобальный объект ссылается undefinedвместоwindow объекта.
  4. Объект, который стоит перед точкой, является тем, к чему будет привязано ключевое слово this.
  5. Мы можем установить значение этого явно с call(),bind() иapply()
  6. Когда new ключевое слово (конструктор), оно привязывается к создаваемому новому объекту.
  7. Функции со стрелками не связываются this - вместо этого они thisсвязаны лексически (т.е. основаны на исходном контексте)

Как подсказывает большинство ответов, мы можем использовать функцию Arrow или bind()Method или Self var. Я бы процитировал пункт о лямбдах (функция стрелки) из руководства по стилю Google JavaScript

Предпочитайте использовать функции стрелок над f.bind (это), и особенно над goog.bind (f, это). Избегайте писать 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. стрелка-функции-против-безвыходном
Code_Mode
источник
Этот вопрос конкретно об использовании функций / методов в качестве обратных вызовов. Ваш ответ может быть лучше подходит для 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, вам понадобится babel и соответствующий плагин babel для его обработки, как сейчас (08/2018).

skyboyer
источник
2
Именно так я и работал в Typescript: public methodName = (params) => { body }внутри класса.
yeyeyerman
5

Другим подходом, который является стандартным способом связывания DOM2this внутри прослушивателя событий, позволяющим всегда удалять прослушиватель (среди других преимуществ), является 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:

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

  1. Когда функция создается с помощью ключевого слова function, значение 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в данном случае.
Виллем ван дер Веен
источник