Я изучаю, как значение this связывается в JavaScript. В следующем примере правильно ли сказать, что «это» связывается с методом getFriends() вместо объекта «детали», что является причиной того, что this.name = «» вместо this.name = «Джо»?
const details = {
name: 'Joe',
friends: [ 'Bob', 'Alex' ],
getFriends: function() {
this.friends.forEach( function( friend ) {
console.info( this.name + " is friends with " + friend );
} );
}
};
details.getFriends();
// Output:
// is friends with Bob
// is friends with Alex
Насколько я понял из своих исследований, «это» не привязывает ни на один уровень вверх в родительской области, верно? Это одно из преимуществ использования стрелочных функций, которые связывают this с родительской областью.



![Безумие обратных вызовов в javascript [JS]](https://i.imgur.com/WsjO6zJb.png)


Нет, когда вы запускаете код таким образом, this указывает на глобальный объект окна. Вы можете console.info значение this. Чтобы проверить это, вы также можете поместить ключ my_name в окно (не используйте имя, так как оно используется окном). Теперь, когда вы запустите код, вы увидите глобальное:
const details = {
my_name: 'Joe',
friends: [ 'Bob', 'Alex' ],
getFriends: function() {
this.friends.forEach( function( friend ) {
console.info( this.my_name + " is friends with " + friend );
} );
}
};
window.my_name = "What?"
details.getFriends();К вашему сведению: forEach принимает второе значение, которое вы можете использовать, чтобы указать, что this будет в обратном вызове. Так это работает, например:
const details = {
my_name: 'Joe',
friends: [ 'Bob', 'Alex' ],
getFriends: function() {
this.friends.forEach( function( friend ) {
console.info( this.my_name + " is friends with " + friend );
}, this ); //<-- pass this into the forEach
}
};
details.getFriends();Конечно, вы всегда можете использовать функцию стрелки.
Цитата из w3schools
In a method, this refers to the owner object.
Alone, this refers to the global object.
In a function, this refers to the global object.
In a function, in strict mode, this is undefined.
In an event, this refers to the element that received the event.
Methods like call(), and apply() can refer this to any object.
https://www.w3schools.com/js/js_this.asp
Ключевое слово this относится к контексту выполнения ток.
По умолчанию this в функции установлен в глобальный контекст, который всегда является объектом окна в браузере:
function foo() {
return this;
}
console.assert(foo() === window);Однако при вызове в качестве конструктора оператор new устанавливает this объект, созданный из прототипа функции. Этот контекст уникален для каждого экземпляра.
function foo() {
return this;
}
console.assert(new foo() !== window);
console.assert(new foo() !== new foo());Когда у объекта есть метод, this в этом методе по умолчанию является этим объектом:
const question = {
ask: function () {
return this;
}
};
console.assert(question.ask() === question);Теперь вот почему важен контекст выполнения ток.
Если вы возьмете этот метод за пределы его объекта, тогда этот контекст метода по умолчанию будет глобальным контекстом:
const question = {
ask: function () {
return this;
}
};
const ask = question.ask;
console.assert(ask() === window);Чтобы решить эту проблему, вы можете использовать bind, call или apply:
const question = {
ask: function () {
return this;
}
};
const ask = question.ask;
console.assert(ask.bind(question)() === question);
console.assert(ask.call(question) === question);
console.assert(ask.apply(question) === question);Вы, должно быть, слышали о стрелочных функциях, которые привязывают this к контексту, который был доступен во время определения функции.
Раньше нам приходилось сохранять this в переменной (обычно называемой that), чтобы ссылаться на правильный контекст. (Или используйте bind.)
function foo() {
const that = this;
// By the time the function executes, the execution context
// will be different even though we invoked the function
// as a constructor.
setTimeout(function () {
console.assert(that !== this);
console.assert(this === window);
}, 100);
}
new foo();Эта техника устарела с функциями стрелок:
function foo() {
setTimeout(() => {
console.assert(this !== window);
}, 100);
}
new foo();Однако помните, что функции имеют лексическую область видимости, поэтому нет даст вам ожидаемый результат:
const question = {
ask: () => {
return this;
}
};
console.assert(question.ask() === window);Почему? Во время определения стрелочной функции единственным контекстом, доступным в лексической области видимости, был глобальный контекст.
Отличный ответ. Эта цитата действительно хорошо объясняет все различные привязки ключевого слова «этот». Спасибо за помощь! :)