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
's this
.
Примечание. При связывании контекста для jQuery вместо этого используйте jQuery.proxy
[docs] . Причина этого заключается в том, что вам не нужно сохранять ссылку на функцию при отмене обратного вызова события. jQuery обрабатывает это внутренне.
В 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
, как правило, упоминается в документации этой функции / метода. Например, метод $.ajax
jQuery [docs] описывает параметр, называемый context
:
Этот объект станет контекстом всех обратных вызовов, связанных с Ajax.
Общая проблема: использование объектных методов в качестве обработчиков обратных вызовов / событий
Еще одно распространенное проявление этой проблемы - когда объектный метод используется как обработчик обратного вызова / события , Функции являются первоклассными гражданами в JavaScript, а термин «метод» - просто разговорный термин для функции, которая является значением свойства объекта. Но эта функция не имеет конкретной ссылки на ее «содержащий» объект.
Рассмотрим следующий пример:
function Foo() { this.data = 42, document.body.onclick = this.method; } Foo.prototype.method = function() { console.log(this.data); };
Функция
this.method
назначается как обработчик события click , но если щелкнутьdocument.body
, зарегистрированное значение будетundefined
, потому что внутри обработчика событияthis
ссылается наdocument.body
, а не на экземплярFoo
. Как уже упоминалось в начале, то, что относится к [49], зависит от того, как называется функция, а не от того, как она определена. Если код выглядит следующим образом, может быть более очевидно, что функция не имеет неявной ссылки на объект: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);
или явно вызвать функцию как «метод» объекта, используя анонимную функцию в качестве обработчика обратного вызова / события и назначить object (
this
) к другой переменной:var self = this; document.body.onclick = function() { self.method(); };
или использовать функцию стрелки:
document.body.onclick = () => this.method();
Мы не можем привязать это к setTimeout()
, поскольку он всегда выполняется с глобальным объектом (Window), если вы хотите получить доступ к контексту this
в функции обратного вызова, а затем с помощью bind()
к функции обратного вызова, которую мы можем достичь как:
setTimeout(function(){
this.methodName();
}.bind(this), 2000);
Термин «контекст» иногда используется для ссылки на объект, на который ссылается this . Его использование неуместно, потому что оно не подходит ни семантически, ни технически с помощью ECMAScript в этом .
«Контекст» означает обстоятельства, окружающие что-то, что добавляет смысл , или некоторая предшествующая и следующая информация, которая дает дополнительный смысл. Термин «контекст» используется в ECMAScript для ссылки на контекст выполнения , который является всеми параметрами, областью действия и этой в рамках некоторого исполняемого кода.
Это показано в разделе 10.4.2 ECMA-262 :
Установите значение ThisBinding на то же значение, что и ThisBinding для контекста выполнения вызова
, в котором четко указано, что этот является частью контекста выполнения.
Контекст выполнения предоставляет информацию, которая добавляет смысл в код, который выполняется , Он содержит гораздо больше информации о том, что только thisBinding .
Таким образом, значение этого не является «контекстом», это всего лишь одна часть выполнения контекст. Это, по сути, локальная переменная, которая может быть задана вызовом любого объекта и в строгом режиме для любого значения вообще.
Это все в «волшебном» синтаксисе вызова метода:
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));
Во-первых, вам нужно иметь четкое представление о scope
и поведении ключевого слова this
в контексте scope
.
this
& amp; scope
:
there are two types of scope in javascript. They are :
1) Global Scope
2) Function Scope
вкратце, глобальная область относится к объекту window.Variables, объявленные в глобальной области, доступны из любого места. С другой стороны, область функций находится внутри функции .variable, объявленный внутри функции, не может быть доступен из внешнего мира в обычном режиме. this
ключевое слово в глобальной области относится к объекту window. Внутренняя функция this
также относится к объекту window.So 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)
}
Теперь давайте создадим экземпляр из конструктора person и вызывать разные версии sayNameVersionX
(X относится к 1,2,3,4) методу с niceCallback
, чтобы увидеть, как много способов управления this
внутри обратного вызова ссылаться на person
.
var p1 = new Person('zami') // create an instance of Person constructor
Что нужно сделать, это создать новую функцию с ключевым словом this
, установленным на предоставленное значение.
sayNameVersion1
и sayNameVersion2
используют bind для управления 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, а не на объект окна.
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)
bind()
. 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));
function MyConstructor(data, transport) {
var self = this;
this.data = data;
transport.on('data', function() {
alert(self.data);
});
}
function MyConstructor(data, transport) {
this.data = data;
transport.on('data', () => {
alert(this.data);
});
}
Отличные ответы выше. Я хочу только добавить, что внутри области вашей функции вы можете присвоить значение этой переменной переменной let self = this;
, а затем внутри обратного вызова просто обратиться к данным типа self.data
.
Ваш код :
function MyConstructor(data, transport) {
this.data = data;
let self = this; //ADD THIS LINE
transport.on('data', function () {
alert(self.data); //USE IT LIKE THIS
});
}
// Mock transport object
var transport = {
on: function(event, callback) {
setTimeout(callback, 1000);
}
};
// called as
var obj = new MyConstructor('foo', transport);
self
иthat
для ссылки наthis
. Я так чувствую, потому чтоthis
- перегруженная переменная, используемая в разных контекстах; тогда какself
обычно соответствует локальному экземпляру, аthat
обычно относится к другому объекту. Я знаю, что вы не установили это правило, поскольку я видел, что он появился в ряде других мест, но именно поэтому я начал использовать_this
, но не уверен, как это себя чувствуют другие, - это была обычная практика. – vol7ron 12 September 2014 в 16:39Function.prototype.call ()
иFunction.prototype.apply ()
. В частности, сapply ()
у меня много пробега. Я менее склонен использоватьbind ()
, возможно, только из привычки, хотя я знаю (но не уверен), что могут быть небольшие накладные преимущества при использовании привязки по другим параметрам. – Nolo 15 November 2016 в 07:02() => this.clicked()
;) – alphanumeric0101 25 May 2018 в 20:36