Я заметил, что, похоже, нет четкого объяснения того, что такое ключевое слово this
и как оно правильно (и неправильно) используется в JavaScript.
Я наблюдал за этим очень странное поведение и не понял, почему это произошло.
Как работает this
и когда он должен использоваться?
Я рекомендую сначала прочитать статью Майка Уэста " Область применения в JavaScript (зеркало)". Это отличное, дружественное введение в концепции this
и цепочки областей действия в JavaScript.
Как только вы начинаете привыкать к this
, правила на самом деле довольно просты. Стандарт ECMAScript 5.1 определяет this
:
§11.1.1 Ключевое слово
this
Ключевое слово
this
оценивает значение ThisBinding текущего контекста выполнения.
ThisBinding - это то, что поддерживает интерпретатор JavaScript при оценке кода JavaScript, например, специальный регистр ЦП, который содержит ссылку на объект. Интерпретатор обновляет ThisBinding каждый раз, когда устанавливает контекст выполнения только в одном из трех разных случаев:
Это касается кода JavaScript, который оценивается на верхнем уровне, например, когда он находится непосредственно внутри <script>
:
<script>
alert("I'm evaluated in the initial global execution context!");
setTimeout(function () {
alert("I'm NOT evaluated in the initial global execution context.");
}, 1);
</script>
При оценке кода в начальном глобальном контексте выполнения ThisBinding устанавливается на глобальный объект, window
(§10.4.1.1).
… Прямым вызовом eval()
ThisBinding остается без изменений; это то же значение, что и ThisBinding для вызывающего контекста выполнения (§10.4.2 (2) (a)).
… Если не прямым вызовом eval()
ThisBinding устанавливается для глобального объекта, как если бы он выполнялся в начальном глобальном контексте выполнения (§10.4.2 (1)).
§15.1.2.1.1 определяет, что такое прямой вызов eval()
. По сути, eval(...)
- это прямой вызов, тогда как что-то вроде (0, eval)(...)
или var indirectEval = eval; indirectEval(...);
var indirectEval = eval; indirectEval(...);
это косвенный вызов eval()
. Смотрите ответ chuckj на (1, eval) ('this') против eval ('this') в JavaScript? и Дмитрий Сошниковых ECMA-262-5 в деталях. Глава 2. Строгий режим. когда вы можете использовать косвенный вызов eval()
.
Это происходит при вызове функции. Если функция вызывается для объекта, например, в obj.myMethod()
или эквивалентном obj["myMethod"]()
, тогда ThisBinding устанавливается на объект (obj
в примере; §13.2.1). В большинстве других случаев ThisBinding устанавливается на глобальный объект (§10.4.3).
Причина написания "в большинстве других случаев" заключается в том, что есть восемь встроенных функций ECMAScript 5, которые позволяют указывать ThisBinding в списке аргументов. Эти специальные функции принимают так называемый thisArg
который становится ThisBinding при вызове функции (§10.4.3).
Эти специальные встроенные функции:
Function.prototype.apply( thisArg, argArray )
Function.prototype.call( thisArg [, arg1 [, arg2,... ] ] )
Function.prototype.bind( thisArg [, arg1 [, arg2,... ] ] )
Array.prototype.every( callbackfn [, thisArg ] )
Array.prototype.some( callbackfn [, thisArg ] )
Array.prototype.forEach( callbackfn [, thisArg ] )
Array.prototype.map( callbackfn [, thisArg ] )
Array.prototype.filter( callbackfn [, thisArg ] )
В случае Function.prototype
они вызываются для объекта функции, но вместо установки ThisBinding для объекта функции ThisBinding устанавливается в thisArg
.
В случае функций Array.prototype
данный callbackfn
вызывается в контексте выполнения, где ThisBinding установлен в thisArg
если он предоставлен; в противном случае к глобальному объекту.
Это правила для простого JavaScript. Когда вы начнете использовать библиотеки JavaScript (например, jQuery), вы можете обнаружить, что некоторые библиотечные функции манипулируют значением this
. Разработчики этих библиотек JavaScript делают это, потому что это имеет тенденцию поддерживать самые распространенные варианты использования, и пользователи библиотеки обычно считают такое поведение более удобным. При передаче функций обратного вызова, ссылающихся на this
библиотечным функциям, вы должны ссылаться на документацию для любых гарантий того, каково значение this
при вызове функции.
Если вам интересно, как библиотека JavaScript манипулирует значением this
, библиотека просто использует одну из встроенных функций JavaScript, принимающих thisArg
. Вы также можете написать свою собственную функцию с функцией обратного вызова и thisArg
:
function doWork(callbackfn, thisArg) {
//...
if (callbackfn != null) callbackfn.call(thisArg);
}
Это особый случай, о котором я еще не упомянул. При создании нового объекта с помощью оператора new
интерпретатор JavaScript создает новый пустой объект, устанавливает некоторые внутренние свойства и затем вызывает функцию конструктора для нового объекта. Таким образом, когда функция вызывается в контексте конструктора, значением this
является новый объект, созданный интерпретатором:
function MyType() {
this.someData = "a string";
}
var instance = new MyType();
// Kind of like the following, but there are more steps involved:
// var instance = {};
// MyType.call(instance);
Функции стрелок (введенные в ECMA6) изменяют объем this
. См. Существующий канонический вопрос: функция Arrow против объявления/выражения функции: являются ли они эквивалентными/заменяемыми? для дополнительной информации. Но вкратце:
Функции стрелки не имеют свои собственные
this
.... переплета. Вместо этого эти идентификаторы разрешаются в лексической области, как и любая другая переменная. Это означает, что внутри функции стрелкиthis
... ссылается на значенияthis
в среде, в которой определена функция стрелки.
Чтобы раскрыть ответы, наведите курсор мыши на светло-желтые прямоугольники.
Какова ценность this
в отмеченной линии? Зачем?
window
- отмеченная строка оценивается в начальном глобальном контексте выполнения.
if (true) {
// What is 'this' here?
}
Каково значение this
в отмеченной строке при выполнении obj.staticFunction()
? Зачем?
obj
- при вызове функции для объекта ThisBinding устанавливается для объекта.
var obj = {
someData: "a string"
};
function myFun() {
return this // What is 'this' here?
}
obj.staticFunction = myFun;
console.log("this is window:", obj.staticFunction() == window);
console.log("this is obj:", obj.staticFunction() == obj);
Какова ценность this
в отмеченной линии? Зачем?
window
В этом примере интерпретатор JavaScript вводит код функции, но поскольку
myFun
/obj.myMethod
не вызывается для объекта, ThisBinding установлен вwindow
.Это отличается от Python, в котором доступ к методу (
obj.myMethod
) создает связанный объект метода.
var obj = {
myMethod: function () {
return this; // What is 'this' here?
}
};
var myFun = obj.myMethod;
console.log("this is window:", myFun() == window);
console.log("this is obj:", myFun() == obj);
Какова ценность this
в отмеченной линии? Зачем?
window
Этот был хитрым. При оценке eval-кода
this
obj
. Однако в eval-кодеmyFun
не вызывается для объекта, поэтому ThisBinding установлен вwindow
для вызова.
function myFun() {
return this; // What is 'this' here?
}
var obj = {
myMethod: function () {
eval("myFun()");
}
};
Какова ценность this
в отмеченной линии? Зачем?
obj
Строка
myFun.call(obj);
вызывает специальную встроенную функциюFunction.prototype.call()
, которая принимаетthisArg
в качестве первого аргумента.
function myFun() {
return this; // What is 'this' here?
}
var obj = {
someData: "a string"
};
console.log("this is window:", myFun.call(obj) == window);
console.log("this is obj:", myFun.call(obj) == obj);
Ключевое слово this
ведет себя по-разному в JavaScript по сравнению с другим языком. В объектно-ориентированных языках ключевое слово this
относится к текущему экземпляру класса. В JavaScript значение this
определяется главным образом контекстом вызова функции (context.function()
) и где он вызывается.
1. При использовании в глобальном контексте
Когда вы используете this
в глобальном контексте, он привязан к глобальному объекту (window
в браузере)
document.write(this); //[object Window]
Когда вы используете this
внутри функции, определенной в глобальном контексте, this
по-прежнему привязан к глобальному объекту, так как функция фактически является методом глобального контекста.
function f1()
{
return this;
}
document.write(f1()); //[object Window]
Выше f1
делается метод глобального объекта. Таким образом, мы можем также называть его объектом window
следующим образом:
function f()
{
return this;
}
document.write(window.f()); //[object Window]
2. При использовании внутри метода объекта
Когда вы используете ключевое слово this
внутри метода объекта, this
привязан к "непосредственному" закрывающему объекту.
var obj = {
name: "obj",
f: function () {
return this + ":" + this.name;
}
};
document.write(obj.f()); //[object Object]:obj
Выше я положил слово в двойные кавычки. Следует сказать, что если вы вставляете объект в другой объект, то this
привязан к непосредственному родительскому объекту.
var obj = {
name: "obj1",
nestedobj: {
name:"nestedobj",
f: function () {
return this + ":" + this.name;
}
}
}
document.write(obj.nestedobj.f()); //[object Object]:nestedobj
Даже если вы явно добавляете функцию к объекту в качестве метода, он по-прежнему следует выше правил, то есть this
все еще указывает на непосредственный родительский объект.
var obj1 = {
name: "obj1",
}
function returnName() {
return this + ":" + this.name;
}
obj1.f = returnName; //add method to object
document.write(obj1.f()); //[object Object]:obj1
3. При вызове функции без контекста
Когда вы используете внутреннюю функцию this
, которая вызывается без какого-либо контекста (т.е. не на каком-либо объекте), она привязана к глобальному объекту (window
в браузере) (даже если функция определена внутри объекта).
var context = "global";
var obj = {
context: "object",
method: function () {
function f() {
var context = "function";
return this + ":" +this.context;
};
return f(); //invoked without context
}
};
document.write(obj.method()); //[object Window]:global
Пробовал все с функциями
Мы также можем попробовать выше точки с функциями. Однако есть некоторые отличия.
this
. для их указания.new
.Ниже я опробовал все, что мы делали с Object и this
выше, но сначала создав функцию вместо прямой записи объекта.
/*********************************************************************
1. When you add variable to the function using this keyword, it
gets added to the function prototype, thus allowing all function
instances to have their own copy of the variables added.
*********************************************************************/
function functionDef()
{
this.name = "ObjDefinition";
this.getName = function(){
return this+":"+this.name;
}
}
obj1 = new functionDef();
document.write(obj1.getName() + "<br />"); //[object Object]:ObjDefinition
/*********************************************************************
2. Members explicitly added to the function protorype also behave
as above: all function instances have their own copy of the
variable added.
*********************************************************************/
functionDef.prototype.version = 1;
functionDef.prototype.getVersion = function(){
return "v"+this.version; //see how this.version refers to the
//version variable added through
//prototype
}
document.write(obj1.getVersion() + "<br />"); //v1
/*********************************************************************
3. Illustrating that the function variables added by both above
ways have their own copies across function instances
*********************************************************************/
functionDef.prototype.incrementVersion = function(){
this.version = this.version + 1;
}
var obj2 = new functionDef();
document.write(obj2.getVersion() + "<br />"); //v1
obj2.incrementVersion(); //incrementing version in obj2
//does not affect obj1 version
document.write(obj2.getVersion() + "<br />"); //v2
document.write(obj1.getVersion() + "<br />"); //v1
/*********************************************************************
4. `this` keyword refers to the immediate parent object. If you
nest the object through function prototype, then `this` inside
object refers to the nested object not the function instance
*********************************************************************/
functionDef.prototype.nestedObj = { name: 'nestedObj',
getName1 : function(){
return this+":"+this.name;
}
};
document.write(obj2.nestedObj.getName1() + "<br />"); //[object Object]:nestedObj
/*********************************************************************
5. If the method is on an object prototype chain, `this` refers
to the object the method was called on, as if the method was on
the object.
*********************************************************************/
var ProtoObj = { fun: function () { return this.a } };
var obj3 = Object.create(ProtoObj); //creating an object setting ProtoObj
//as its prototype
obj3.a = 999; //adding instance member to obj3
document.write(obj3.fun()+"<br />");//999
//calling obj3.fun() makes
//ProtoObj.fun() to access obj3.a as
//if fun() is defined on obj3
4. При использовании внутри конструкторской функции.
Когда функция используется как конструктор (то есть, когда она вызывается с ключевым словом new
), тело this
внутри тела функции указывает на новый объект, который создается.
var myname = "global context";
function SimpleFun()
{
this.myname = "simple function";
}
var obj1 = new SimpleFun(); //adds myname to obj1
//1. `new` causes `this` inside the SimpleFun() to point to the
// object being constructed thus adding any member
// created inside SimipleFun() using this.membername to the
// object being constructed
//2. And by default `new` makes function to return newly
// constructed object if no explicit return value is specified
document.write(obj1.myname); //simple function
5. При использовании внутренней функции, определенной в цепочке прототипов
Если метод находится в цепочке прототипов объекта, this
внутри такого метода ссылается на объект, на который был вызван метод, как если бы метод был определен на объекте.
var ProtoObj = {
fun: function () {
return this.a;
}
};
//Object.create() creates object with ProtoObj as its
//prototype and assigns it to obj3, thus making fun()
//to be the method on its prototype chain
var obj3 = Object.create(ProtoObj);
obj3.a = 999;
document.write(obj3.fun()); //999
//Notice that fun() is defined on obj3 prototype but
//`this.a` inside fun() retrieves obj3.a
6. Внутри вызовов(), apply() и bind() функции
Function.prototype
.this
, которое будет использоваться во время выполнения функции. Они также принимают любые параметры, которые должны быть переданы исходной функции при ее вызове.fun.apply(obj1 [, argsArray])
Устанавливает obj1
как значение this
внутри fun()
и вызывает fun()
передачу элементов argsArray
в качестве своих аргументов.fun.call(obj1 [, arg1 [, arg2 [,arg3 [, ...]]]])
- устанавливает obj1
как значение this
внутри fun()
и вызывает fun()
передачу arg1, arg2, arg3, ...
в качестве своих аргументов.fun.bind(obj1 [, arg1 [, arg2 [,arg3 [, ...]]]])
. Возвращает ссылку на функцию fun
с this
внутри fun, привязанную к obj1
, а параметры fun
связаны с указанными параметрами arg1, arg2, arg3,...
.apply
, call
и bind
должна стать очевидной. apply
позволяет указывать аргументы для функции как объект, подобный массиву, то есть объект с числовым свойством length
и соответствующими неотрицательными целыми свойствами. В то время как call
позволяет напрямую указывать аргументы функции. Оба apply
и call
немедленно вызывают функцию в указанном контексте и с указанными аргументами. С другой стороны, bind
просто возвращает функцию, связанную с указанным значением this
и аргументами. Мы можем записать ссылку на эту возвращенную функцию, присвоив ее переменной, и позже мы можем ее вызвать в любое время.function add(inc1, inc2)
{
return this.a + inc1 + inc2;
}
var o = { a : 4 };
document.write(add.call(o, 5, 6)+"<br />"); //15
//above add.call(o,5,6) sets `this` inside
//add() to `o` and calls add() resulting:
// this.a + inc1 + inc2 =
// `o.a` i.e. 4 + 5 + 6 = 15
document.write(add.apply(o, [5, 6]) + "<br />"); //15
// `o.a` i.e. 4 + 5 + 6 = 15
var g = add.bind(o, 5, 6); //g: `o.a` i.e. 4 + 5 + 6
document.write(g()+"<br />"); //15
var h = add.bind(o, 5); //h: `o.a` i.e. 4 + 5 + ?
document.write(h(6) + "<br />"); //15
// 4 + 5 + 6 = 15
document.write(h() + "<br />"); //NaN
//no parameter is passed to h()
//thus inc2 inside add() is `undefined`
//4 + 5 + undefined = NaN</code>
7. this
внутри обработчиков событий
this
непосредственно внутри функции обработки событий относится к соответствующему элементу. Такое прямое назначение функций может быть выполнено с использованием метода addeventListener
или с помощью традиционных методов регистрации событий, таких как onclick
.this
непосредственно внутри свойства события (например, <button onclick="...this..." >
) элемента, он ссылается на элемент.this
косвенно через другую функцию, вызываемую внутри функции обработки событий или свойства события, разрешается глобальному объекту window
.attachEvent
. Вместо того, чтобы назначать функцию обработчику события (и тем самым создавать функциональный метод элемента), он вызывает функцию в событии (фактически вызывая его в глобальном контексте).Я рекомендую лучше попробовать это в JSFiddle.
<script>
function clickedMe() {
alert(this + " : " + this.tagName + " : " + this.id);
}
document.getElementById("button1").addEventListener("click", clickedMe, false);
document.getElementById("button2").onclick = clickedMe;
document.getElementById("button5").attachEvent('onclick', clickedMe);
</script>
<h3>Using `this` "directly" inside event handler or event property</h3>
<button id="button1">click() "assigned" using addEventListner() </button><br />
<button id="button2">click() "assigned" using click() </button><br />
<button id="button3" onclick="alert(this+ ' : ' + this.tagName + ' : ' + this.id);">used `this` directly in click event property</button>
<h3>Using `this` "indirectly" inside event handler or event property</h3>
<button onclick="alert((function(){return this + ' : ' + this.tagName + ' : ' + this.id;})());">`this` used indirectly, inside function <br /> defined & called inside event property</button><br />
<button id="button4" onclick="clickedMe()">`this` used indirectly, inside function <br /> called inside event property</button> <br />
IE only: <button id="button5">click() "attached" using attachEvent() </button>
<script>
function clickedMe() {
alert(this + " : " + this.tagName + " : " + this.id);
}
document.getElementById("button1").addEventListener("click", clickedMe, false);
document.getElementById("button2").onclick = clickedMe;
document.getElementById("button5").attachEvent('onclick', clickedMe);
</script>
<h3>Using `this` "directly" inside event handler or event property</h3>
<button id="button1">click() "assigned" using addEventListner() </button><br />
<button id="button2">click() "assigned" using click() </button><br />
<button id="button3" onclick="alert(this+ ' : ' + this.tagName + ' : ' + this.id);">used `this` directly in click event property</button>
<h3>Using `this` "indirectly" inside event handler or event property</h3>
<button onclick="alert((function(){return this + ' : ' + this.tagName + ' : ' + this.id;})());">`this` used indirectly, inside function <br /> defined & called inside event property</button><br />
<button id="button4" onclick="clickedMe()">`this` used indirectly, inside function <br /> called inside event property</button> <br />
IE only: <button id="button5">click() "attached" using attachEvent() </button>
this
не устанавливается вызовом. Так как код не находится в строгом режиме, значение this
всегда должно быть объектом, поэтому по умолчанию используется глобальный объект. И на самом деле именно поэтому я подумал, что мы можем напрямую вызвать window.f1()
, так что это означает, что f1()
уже присоединена к объекту window
, я имею в виду перед вызовом. Я правильно понял?
this
Рассмотрим следующую функцию:
function foo() {
console.log("bar");
console.log(this);
}
foo(); // calling the function
Обратите внимание, что мы запускаем это в обычном режиме, т.е. строгий режим не используется.
При запуске в браузере значение this
будет регистрироваться как window
. Это связано с тем, что window
является глобальной переменной в области веб-браузера.
Если вы запустите этот же фрагмент кода в среде, такой как node.js, this
будет ссылаться на глобальную переменную в вашем приложении.
Теперь, если мы запустим это в строгом режиме, добавив оператор "use strict";
в начало объявления функции, this
больше не будет ссылаться на глобальную переменную в любом из envirnoments. Это делается для того, чтобы избежать путаницы в строгом режиме. this
, в этом случае просто log undefined
, потому что это то, что он есть, он не определен.
В следующих случаях мы увидим, как манипулировать значением this
.
Существуют разные способы сделать это. Если вы вызывали собственные методы в Javascript, например forEach
и slice
, вы уже должны знать, что переменная this
в этом случае относится к Object
, на которую вы вызывали эту функцию (обратите внимание, что в javascript, примерно все это Object
, включая Array
и Function
s). Возьмите следующий код, например.
var myObj = {key: "Obj"};
myObj.logThis = function () {
// I am a method
console.log(this);
}
myObj.logThis(); // myObj is logged
Если a Object
содержит свойство, которое содержит a Function
, свойство называется методом. Этот метод при вызове всегда будет иметь переменную this
, установленную в Object
, с которой она связана. Это верно как для строгих, так и для нестрогих режимов.
Обратите внимание, что если метод хранится (или, скорее, копируется) в другой переменной, ссылка на this
больше не сохраняется в новой переменной. Например:
// continuing with the previous code snippet
var myVar = myObj.thisMethod;
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
будет присвоен protoype Person.prototype
. Это означает, что любой метод или свойство прототипа Person
будет доступен для всех экземпляров Person
, включая awal
.Person
вызывается; this
является ссылкой на вновь построенный объект awal
.Pretty straighforward, eh?
Обратите внимание, что в официальной спецификации ECMAScript нет где указано, что такие типы функций являются действительными constructor
функциями. Они являются просто нормальными функциями, а new
может использоваться для любой функции. Просто мы используем их как таковые, поэтому мы называем их только такими.
call
и apply
Так что да, поскольку Function
также 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
, установленное вызовом метода dot, которое мы обсуждали во второй пуле.
Достаточно просто:)
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
по умолчанию?new
?this
с помощью call
и apply
?bind
.this
для решения проблем с вложенными областями.new
ключевом слове? Также этот вопрос был забит до смерти, но у всех нас есть «то время, когда мы пытались оседлать вопрос, на который ответили 4 года назад»
"this" - все о сфере видимости. Каждая функция имеет свой собственный объем, и поскольку все в JS является объектом, даже функция может хранить некоторые значения в себе, используя "this". OOP 101 учит, что "this" применим только к экземплярам объекта. Поэтому каждый раз, когда выполняется функция, новый "экземпляр" этой функции имеет новое значение "this".
Большинство людей путают, когда они пытаются использовать "this" внутри анонимных функций закрытия, например:
(function(value) { this.value = value; $('.some-elements').each(function(elt){ elt.innerHTML = this.value; // uh oh!! possibly undefined }); })(2);
Итак, внутри each(), "this" не удерживает "значение", которое вы ожидаете от него (от
this.value = value;над ним). Итак, чтобы справиться с этой проблемой (без каламбуры), разработчик мог:
(function(value) { var self = this; // small change self.value = value; $('.some-elements').each(function(elt){ elt.innerHTML = self.value; // phew!! == 2 }); })(2);
Попробуйте; вам понравится эта схема программирования
Поскольку этот поток натолкнулся, я собрал несколько точек для новых читателей для темы this
.
this
?Мы используем это подобно тому, как мы используем местоимения в естественных языках, таких как английский: "Джон работает быстро, потому что он пытается поймать поезд". Вместо этого мы могли бы написать "... John пытается поймать поезд".
var person = {
firstName: "Penelope",
lastName: "Barrymore",
fullName: function () {
// We use "this" just as in the sentence above:
console.log(this.firstName + " " + this.lastName);
// We could have also written:
console.log(person.firstName + " " + person.lastName);
}
}
this
не присваивается значение, пока объект не вызовет функцию, в которой он определен. В глобальной области действия все глобальные переменные и функции определены в объекте window
. Поэтому this
в глобальной функции ссылается на (и имеет значение) глобальный объект window
.
Когда use strict
, this
в глобальном и в анонимных функциях, не связанных с каким-либо объектом, имеет значение undefined
.
Ключевое слово this
наиболее неправильно понято, когда: 1) мы используем метод, который использует this
, 2), мы назначаем метод который использует this
для переменной, 3) функция, которая использует this
, передается как функция обратного вызова, а 4) this
используется внутри замыкания - внутренней функции. (2)
Определено в ECMA Script 6, функции-стрелки принимают привязку this
от
(функция или глобальная).
function foo() {
// return an arrow function
return (a) => {
// `this` here is lexically inherited from `foo()`
console.log(this.a);
};
}
var obj1 = { a: 2 };
var obj2 = { a: 3 };
var bar = foo.call(obj1);
bar.call( obj2 ); // 2, not 3!
Хотя функции-стрелки предоставляют альтернативу использованию bind()
, важно отметить, что они по существу отключают традиционный механизм this
в пользу более широкого понимания лексического охвата. (1)
Литература:
this
в Javascript всегда ссылается на "владельца" функции , выполняемой.
Если явный владелец не определен, то ссылается на самый верхний владелец - объект окна.
Итак, если я сделал
function someKindOfFunction() {
this.style = 'foo';
}
element.onclick = someKindOfFunction;
this
будет ссылаться на объект элемента. Но будьте осторожны, многие люди делают эту ошибку
<element onclick="someKindOfFunction()">
В последнем случае вы просто ссылаетесь на функцию, а не передаете ее элементу. Поэтому this
будет ссылаться на объект окна.
Каждый контекст выполнения в javascript имеет область контекст, который задается:
Каким бы ни был этот контекст области видимости, ссылается на "this".
Вы можете изменить, что установить значение этой области , используя func.call
, func.apply
или func.bind
.
По умолчанию, и что путает большинство новичков, когда вызывающий callback вызывается после того, как событие добавлено в элемент DOM, контекст области это значение функции является элементом DOM.
jQuery делает это тривиальным для изменения с помощью jQuery.proxy.
this
в Javascript, так это то, что это не внутреннее свойство самой функции, а скорее артефакт того, как эта функция вызывается.
func.call
, func.bind
и т. д. - Sushil
Здесь является одним из хороших источников this
в JavaScript
.
Вот резюме:
global this
В браузере в глобальной области this
находится объект window
<script type="text/javascript">
console.log(this === window); // true
var foo = "bar";
console.log(this.foo); // "bar"
console.log(window.foo); // "bar"
В node
с использованием repl, this
- это верхнее пространство имен. Вы можете ссылаться на него как global
.
>this
{ ArrayBuffer: [Function: ArrayBuffer],
Int8Array: { [Function: Int8Array] BYTES_PER_ELEMENT: 1 },
Uint8Array: { [Function: Uint8Array] BYTES_PER_ELEMENT: 1 },
...
>global === this
true
В node
, выполняющемся из script, this
в глобальной области запускается как пустой объект. Это не то же самое, что global
\\test.js
console.log(this); \\ {}
console.log(this === global); \\ fasle
функция this
За исключением случаев обработчиков событий DOM или когда предоставляется thisArg
(см. ниже), как в node, так и в браузере с использованием this
в функции, которая не вызывается с помощью new
ссылок глобальный охват...
<script type="text/javascript">
foo = "bar";
function testThis() {
this.foo = "foo";
}
console.log(this.foo); //logs "bar"
testThis();
console.log(this.foo); //logs "foo"
</script>
Если вы используете use strict;
, в этом случае this
будет undefined
<script type="text/javascript">
foo = "bar";
function testThis() {
"use strict";
this.foo = "foo";
}
console.log(this.foo); //logs "bar"
testThis(); //Uncaught TypeError: Cannot set property 'foo' of undefined
</script>
Если вы вызываете функцию с new
, this
будет новым контекстом, он не будет ссылаться на глобальный this
.
<script type="text/javascript">
foo = "bar";
function testThis() {
this.foo = "foo";
}
console.log(this.foo); //logs "bar"
new testThis();
console.log(this.foo); //logs "bar"
console.log(new testThis().foo); //logs "foo"
</script>
Функции, которые вы создаете, становятся объектами функции. Они автоматически получают специальное свойство prototype
, которое вы можете присвоить значениям. Когда вы создаете экземпляр, вызывая свою функцию с помощью new
, вы получаете доступ к значениям, присвоенным свойству prototype
. Вы получаете доступ к этим значениям с помощью this
.
function Thing() {
console.log(this.foo);
}
Thing.prototype.foo = "bar";
var thing = new Thing(); //logs "bar"
console.log(thing.foo); //logs "bar"
Как правило, ошибочно назначать массивы или объекты на prototype
. Если вы хотите, чтобы экземпляры имели свои собственные массивы, создайте их в функции, а не прототипе.
function Thing() {
this.things = [];
}
var thing1 = new Thing();
var thing2 = new Thing();
thing1.things.push("foo");
console.log(thing1.things); //logs ["foo"]
console.log(thing2.things); //logs []
Вы можете использовать this
в любой функции объекта, чтобы ссылаться на другие свойства этого объекта. Это не то же самое, что экземпляр, созданный с помощью new
.
var obj = {
foo: "bar",
logFoo: function () {
console.log(this.foo);
}
};
obj.logFoo(); //logs "bar"
В обработчике событий HTML DOM this
всегда ссылается на элемент DOM, событие было прикреплено к
function Listener() {
document.getElementById("foo").addEventListener("click",
this.handleClick);
}
Listener.prototype.handleClick = function (event) {
console.log(this); //logs "<div id="foo"></div>"
}
var listener = new Listener();
document.getElementById("foo").click();
Если вы не bind
контекст
function Listener() {
document.getElementById("foo").addEventListener("click",
this.handleClick.bind(this));
}
Listener.prototype.handleClick = function (event) {
console.log(this); //logs Listener {handleClick: function}
}
var listener = new Listener();
document.getElementById("foo").click();
Внутри атрибутов HTML, в которые вы можете поместить JavaScript, this
является ссылкой на элемент.
<div id="foo" onclick="console.log(this);"></div>
<script type="text/javascript">
document.getElementById("foo").click(); //logs <div id="foo"...
</script>
Вы можете использовать eval
для доступа к this
.
function Thing () {
}
Thing.prototype.foo = "bar";
Thing.prototype.logFoo = function () {
eval("console.log(this.foo)"); //logs "bar"
}
var thing = new Thing();
thing.logFoo();
Вы можете использовать with
, чтобы добавить this
в текущую область действия, чтобы читать и записывать значения на this
без прямого указания this
.
function Thing () {
}
Thing.prototype.foo = "bar";
Thing.prototype.logFoo = function () {
with (this) {
console.log(foo);
foo = "foo";
}
}
var thing = new Thing();
thing.logFoo(); // logs "bar"
console.log(thing.foo); // logs "foo"
jQuery во многих местах имеет this
ссылается на элемент DOM.
<div class="foo bar1"></div>
<div class="foo bar2"></div>
<script type="text/javascript">
$(".foo").each(function () {
console.log(this); //logs <div class="foo...
});
$(".foo").on("click", function () {
console.log(this); //logs <div class="foo...
});
$(".foo").each(function () {
this.click();
});
</script>
Существует много путаницы в отношении того, как "this" ключевое слово интерпретируется в JavaScript. Надеюсь, эта статья заложит все, чтобы отдохнуть раз и навсегда. И многое другое. Пожалуйста, внимательно прочитайте всю статью. Будьте предупреждены, что эта статья длинная.
Независимо от контекста, в котором он используется, "this" всегда ссылается на текущий "текущий объект в Javascript. Однако то, что " текущий объект" отличается в соответствии с контекстом. Контекст может быть в точности 1 из 6 следующим образом:
Ниже описывается каждый из этих контекстов один за другим:
Глобальный контекст (т.е. вне всех функций):
Вне всех функций (т.е. в глобальном контексте) "current объект (и, следовательно, значение "this") всегда "окно" для браузеров.
Внутри прямой "Не привязанная функция" Вызов:
Внутри прямой "Non Bound Function" Call, объект, который вызываемый вызов функции становится "текущим объектом" (и, следовательно, значение "this"). Если функция вызывается без явного текущего объекта, текущий объект является либо "окном (для не строгого режима), либо undefined (для строгого режима). Любая функция (или переменная), определенная в Глобальный контекст автоматически становится свойством объекта "окна. Например, предположим, что функция определена в глобальном контексте как
function UserDefinedFunction(){
alert(this)
}
он становится свойством объекта window, как если бы вы определили это как
window.UserDefinedFunction=function(){
alert(this)
}
В режиме "Не строгого режима" вызов/вызов этой функции непосредственно через "UserDefinedFunction()" будет автоматически вызывать/вызывать он как "window.UserDefinedFunction()" делает "окно" как "текущий объект" (и, следовательно, значение "this") в пределах "UserDefinedFunction" . Включение этой функции в "Non Strict Mode" будет приведет к следующему
UserDefinedFunction() // displays [object Window] as it automatically gets invoked as window.UserDefinedFunction()
В "Строгий режим", вызов/вызов функции непосредственно через "UserDefinedFunction()" будет "NOT" автоматически вызывать/вызывать его как "window.UserDefinedFunction()" .Сохранить текущий объект " (и значение "this") в пределах "UserDefinedFunction" должен быть undefined. Вызов этой функции в "Строгий режим" приведет к следующему
UserDefinedFunction() // displays undefined
Однако, ссылаясь на явное использование окна-объекта, следующие
window.UserDefinedFunction() // "always displays [object Window] irrespective of mode."
Посмотрим на другой пример. Посмотрите следующий код
function UserDefinedFunction()
{
alert(this.a + "," + this.b + "," + this.c + "," + this.d)
}
var o1={
a:1,
b:2,
f:UserDefinedFunction
}
var o2={
c:3,
d:4,
f:UserDefinedFunction
}
o1.f() // Shall display 1,2,undefined,undefined
o2.f() // Shall display undefined,undefined,3,4
В приведенном выше примере мы видим, что когда "UserDefinedFunction" вызывается с помощью o1, "this" принимает значение o1, а значение его свойств "a" и "b" . Значение "c" и "d" были показаны как undefined как o1. не определять эти свойства
Аналогично, когда "UserDefinedFunction" вызывается через o2 "this" принимает значение o2, а значение его свойств "c" и "d" отображается Значение "a" и "b" было показано как undefined, поскольку o2 не определяет эти свойства.
Внутри косвенной "Не привязанной функции" Вызов через functionName.callи functionName.apply:
Когда "Non Bound Function" вызывается через functionName.call или functionName.apply, "текущий объект (и, следовательно, значение "this") устанавливается на значение "this" (первый параметр) передается call/apply. Следующий код демонстрирует то же самое.
function UserDefinedFunction()
{
alert(this.a + "," + this.b + "," + this.c + "," + this.d)
}
var o1={
a:1,
b:2,
f:UserDefinedFunction
}
var o2={
c:3,
d:4,
f:UserDefinedFunction
}
UserDefinedFunction.call(o1) // Shall display 1,2,undefined,undefined
UserDefinedFunction.apply(o1) // Shall display 1,2,undefined,undefined
UserDefinedFunction.call(o2) // Shall display undefined,undefined,3,4
UserDefinedFunction.apply(o2) // Shall display undefined,undefined,3,4
o1.f.call(o2) // Shall display undefined,undefined,3,4
o1.f.apply(o2) // Shall display undefined,undefined,3,4
o2.f.call(o1) // Shall display 1,2,undefined,undefined
o2.f.apply(o1) // Shall display 1,2,undefined,undefined
В приведенном выше коде ясно, что значение "this" для любого "NON Связанная функция "может быть изменена с помощью вызова/применения. Кроме того, если "this" не передается явно в вызов/применение, "текущий объект (и, следовательно, значение "this") установлен в "окно" в нестрочном режиме и "undefined" в строгом режиме.
Внутри функции "Связанная функция" (т.е. функция, связанная вызовом functionName.bind):
Связанная функция - это функция, значение которой "this" исправлено. Следующий код показал, как работает "this" в случае связанной функции
function UserDefinedFunction()
{
alert(this.a + "," + this.b + "," + this.c + "," + this.d)
}
var o1={
a:1,
b:2,
f:UserDefinedFunction,
bf:null
}
var o2={
c:3,
d:4,
f:UserDefinedFunction,
bf:null
}
var bound1=UserDefinedFunction.bind(o1); // permanantly fixes "this" value of function "bound1" to Object o1
bound1() // Shall display 1,2,undefined,undefined
var bound2=UserDefinedFunction.bind(o2); // permanantly fixes "this" value of function "bound2" to Object o2
bound2() // Shall display undefined,undefined,3,4
var bound3=o1.f.bind(o2); // permanantly fixes "this" value of function "bound3" to Object o2
bound3() // Shall display undefined,undefined,3,4
var bound4=o2.f.bind(o1); // permanantly fixes "this" value of function "bound4" to Object o1
bound4() // Shall display 1,2,undefined,undefined
o1.bf=UserDefinedFunction.bind(o2) // permanantly fixes "this" value of function "o1.bf" to Object o2
o1.bf() // Shall display undefined,undefined,3,4
o2.bf=UserDefinedFunction.bind(o1) // permanantly fixes "this" value of function "o2.bf" to Object o1
o2.bf() // Shall display 1,2,undefined,undefined
bound1.call(o2) // Shall still display 1,2,undefined,undefined. "call" cannot alter the value of "this" for bound function
bound1.apply(o2) // Shall still display 1,2,undefined,undefined. "apply" cannot alter the value of "this" for bound function
o2.bf.call(o2) // Shall still display 1,2,undefined,undefined. "call" cannot alter the value of "this" for bound function
o2.bf.apply(o2) // Shall still display 1,2,undefined,undefined."apply" cannot alter the value of "this" for bound function
Как указано в приведенном выше коде, значение "this" для любой "Связанной функции" НЕ МОЖЕТ быть изменен с помощью вызова/применения. Кроме того, если "this" параметр явно не передан для привязки, "текущий объект" (и, следовательно, значение "this") установлено в "окно" в Non строгий режим и "undefined" в строгом режиме. Еще кое-что. Привязка уже связанной функции не изменяет значение "this". Он остается установленным как значение, заданное первой функцией связывания.
Пока создание объекта через "новый" :
Внутри функции-конструктора "текущий объект (и, следовательно, значение "this") ссылается на объект, который в настоящее время создается через "новый" , независимо от статуса привязки функции. Однако если конструктор является связанной функцией, он должен быть вызван с предопределенный набор аргументов, заданных для связанной функции.
Внутренний обработчик событий Inline DOM:
Посмотрите на следующий фрагмент HTML
<button onclick='this.style.color=white'>Hello World</button>
<div style='width:100px;height:100px;' onclick='OnDivClick(event,this)'>Hello World</div>
"this" в приведенных выше примерах относится к элементу "button", а "div" соответственно.
В первом примере цвет шрифта кнопки должен быть установлен на белый при нажатии.
Во втором примере, когда щелкнут элемент "div" , он должен вызовите функцию OnDivClick со своим вторым параметром ссылаясь на элемент с щелчком div. Однако значение "this" в OnDivClick НЕ ДОЛЖЕН ссылаться на нажатый div элемент. Он должен быть установлен как "оконный объект или "undefined" в Нестандартных и Строгих моделях соответственно (если OnDivClick является несвязанной функцией) или установите для предопределенного Связанное значение (если OnDivClick является связанной функцией)
Ниже приведена вся статья
В глобальном контексте "this" всегда ссылается на "окно
Всякий раз, когда вызывается функция, она вызывается в контексте object ("текущий объект). Если текущий объект явно не указан, текущий объект - это "оконный объект в NON Strict Mode и "undefined" в строгом режиме по умолчанию.
Значение "this" внутри функции Non Bound является ссылкой на объект, в контексте которого вызывается функция ("текущий объект" ).
Значение "this" внутри функции Non Bound может быть переопределено вызов и применить методы функции.
Значение "this" фиксировано для функции Bound и не может быть переопределить вызов и применить методы функции.
Связывание и уже связанная функция не изменяет значение "this". Он остается установленным как значение, заданное первой функцией связывания.
Значение "this" внутри конструктора - это объект, который создано и инициализировано
Значение "this" внутри встроенного обработчика событий DOM является ссылкой к элементу, для которого задан обработчик события.
Вероятно, самая подробная и всеобъемлющая статья по this
вопросу:
Нежное объяснение ключевого слова "this" в JavaScript
Идея this
заключается в том, чтобы понять, что типы вызова функций имеют важное значение для установки this
значения.
Когда возникают проблемы с this
, не спрашивайте себя:
Откуда
this
взято?
но спросите себя:
Как вызывается функция?
Для функции стрелки (специальный случай прозрачности контекста) спросите себя:
Какое значение имеет
this
значение, когда определена функция стрелки?
Это мышление правильное, когда вы имеете дело с this
и избавит вас от головной боли.
Даниэль, удивительное объяснение! Несколько слов по этому и хорошему списку указателя контекста выполнения this
в случае обработчиков событий.
В двух словах this
в JavaScript указывает объект, у которого (или из контекста выполнения) текущая функция была запущена, и она всегда доступна только для чтения, вы все равно не можете ее установить (такая попытка закончится с сообщением "Недопустимая левая сторона в присваивании".
Для обработчиков событий: обработчики событий inline, такие как <element onclick="foo">
, переопределяют любые другие обработчики, прикрепленные ранее и раньше, поэтому будьте осторожны и лучше избегайте делегирования событий внутри очереди.
И благодаря Заре Алавердян, которая вдохновила меня на этот список примеров через несогласные дебаты:)
el.onclick = foo; // in the foo - obj
el.onclick = function () {this.style.color = '#fff';} // obj
el.onclick = function() {doSomething();} // In the doSomething -
Window
el.addEventListener('click',foo,false) // in the foo - obj
el.attachEvent('onclick, function () { // this }') // window, all the
compliance to IE :)
<button onclick="this.style.color = '#fff';"> // obj
<button onclick="foo"> // In the foo - window, but you can <button
onclick="foo(this)">
Это лучшее объяснение, которое я видел. Понять JavaScripts с помощью Clarity
Эта ссылка ALLWAYS означает (и содержит значение) объект - особый объект - и обычно используется внутри функции или метода, хотя она может использоваться вне функции в глобальной области. Обратите внимание, что когда мы используем строгий режим, это значение не определено в глобальных функциях и в анонимных функциях, которые не привязаны ни к одному объекту.
Существуют четыре условия, в которых это может ввести в заблуждение:
Он дает примеры кода, объяснения и исправления кода, которые, как я думал, были очень полезными.
В псевдоклассических терминах многие лекции обучают ключевому слову 'this' как объект, созданный конструктором класса или объекта. Каждый раз, когда новый объект создается из класса, представьте, что под капотом создается и возвращается локальный экземпляр объекта 'this'. Я помню, как он учил так:
function Car(make, model, year) {
var this = {}; // under the hood, so to speak
this.make = make;
this.model = model;
this.year = year;
return this; // under the hood
}
var mycar = new Car('Eagle', 'Talon TSi', 1993);
// ========= under the hood
var this = {};
this.make = 'Eagle';
this.model = 'Talon TSi';
this.year = 1993;
return this;
Трудно получить хорошее представление о JS или написать больше, чем что-либо тривиальное в нем, если вы не понимаете его полностью. Вы не можете просто позволить себе быстро окунуться :) Я думаю, что лучший способ начать работу с JS - сначала посмотреть эти видео-лекции Дугласа Крокфорда - http://yuiblog.com/crockford/, который охватывает это и то, и все остальное о JS.
Значение "this" зависит от "контекста", в котором выполняется функция. Контекстом может быть любой объект или глобальный объект, т.е. Окно.
Таким образом, семантика "this" отличается от традиционных языков ООП. И это вызывает проблемы: 1. когда функция передается другой переменной (скорее всего, обратный вызов); и 2. когда замыкание вызывается из метода-члена класса.
В обоих случаях это устанавливается как окно.
this
- одна из неправильно понятых концепций в JavaScript, потому что она ведет себя немного иначе, чем место. Просто this
относится к "владельцу" функции, которую мы сейчас выполняем.
this
помогает получить текущий объект (контекст выполнения a.k.a.), с которым мы работаем. Если вы понимаете, в каком объекте выполняется текущая функция, вы можете легко понять, что текущий this
var val = "window.val"
var obj = {
val: "obj.val",
innerMethod: function () {
var val = "obj.val.inner",
func = function () {
var self = this;
return self.val;
};
return func;
},
outerMethod: function(){
return this.val;
}
};
//This actually gets executed inside window object
console.log(obj.innerMethod()()); //returns window.val
//Breakdown in to 2 lines explains this in detail
var _inn = obj.innerMethod();
console.log(_inn()); //returns window.val
console.log(obj.outerMethod()); //returns obj.val
Выше мы создаем 3 переменные с одинаковым именем "val". Один в глобальном контексте, один внутри obj и другой внутри innerMethod obj. JavaScript разрешает идентификаторы в определенном контексте, поднимая цепочку областей действия из локального глобального.
Несколько мест, где this
можно дифференцировать
var status = 1;
var helper = {
status : 2,
getStatus: function () {
return this.status;
}
};
var theStatus1 = helper.getStatus(); //line1
console.log(theStatus1); //2
var theStatus2 = helper.getStatus;
console.log(theStatus2()); //1
Когда выполняется строка1, JavaScript устанавливает контекст выполнения (EC) для вызова функции, устанавливая this
объекту , на который ссылается все, что было до последнего ".. поэтому в последней строке вы можете понять, что a()
был выполнен в глобальном контексте, который является window
.
this
может использоваться для ссылки на создаваемый объект
function Person(name){
this.personName = name;
this.sayHello = function(){
return "Hello " + this.personName;
}
}
var person1 = new Person('Scott');
console.log(person1.sayHello()); //Hello Scott
var person2 = new Person('Hugh');
var sayHelloP2 = person2.sayHello;
console.log(sayHelloP2()); //Hello undefined
Когда выполняется новый Person()
, создается совершенно новый объект. Person
вызывается, а его this
устанавливается для ссылки на этот новый объект.
function testFunc() {
this.name = "Name";
this.myCustomAttribute = "Custom Attribute";
return this;
}
var whatIsThis = testFunc();
console.log(whatIsThis); //window
var whatIsThis2 = new testFunc();
console.log(whatIsThis2); //testFunc() / object
console.log(window.myCustomAttribute); //Custom Attribute
Если мы пропустим ключевое слово new
, whatIsThis
ссылается на самый глобальный контекст, он может найти (window
)
Если обработчик события inline, this
относится к глобальному объекту
<script type="application/javascript">
function click_handler() {
alert(this); // alerts the window object
}
</script>
<button id='thebutton' onclick='click_handler()'>Click me!</button>
При добавлении обработчика событий через JavaScript this
относится к элементу DOM, который сгенерировал событие.
.apply()
.call()
и .bind()
var that = this
в JavaScriptНемного информации об этом ключевом слове
Позвольте записывать this
ключевое слово в консоль в глобальной области без какого-либо кода, но
console.log(this)
В Client/Browser this
ключевое слово - глобальный объект, который является window
console.log(this === window) // true
а также
В среде выполнения Server/Node/Javascript this
ключевое слово также является глобальным объектом, который является module.exports
console.log(this === module.exports) // true
console.log(this === exports) // true
Имейте в виду, что exports
- это просто ссылка на module.exports
Может ли this помочь? (Большая часть путаницы 'this' в javascript исходит из того факта, что она вообще не связана с вашим объектом, а с текущей исполняемой областью - это может быть не совсем так, как это работает, но мне всегда кажется, см. статью для полного объяснения)
это использование для области видимости как это
<script type="text/javascript" language="javascript">
$('#tbleName tbody tr').each(function{
var txt='';
txt += $(this).find("td").eq(0).text();
\\same as above but synatx different
var txt1='';
txt1+=$('#tbleName tbody tr').eq(0).text();
alert(txt1)
});
</script>
значение txt1 и txt равно В приведенном выше примере $ (this) = $('# tbleName tbody tr') - это тот же
У меня есть другое мнение об this
из других ответов, которые, я надеюсь, будут полезны.
Один из способов взглянуть на JavaScript - это увидеть только 1 способ вызова функции 1. это
functionObject.call(objectForThis, arg0, arg1, arg2, ...);
Для objectForThis
всегда objectForThis
какое-то значение.
Все остальное является синтаксическим сахаром для functionObject.call
Итак, все остальное можно описать тем, как оно переводится в functionObject.call
.
Если вы просто вызываете функцию, то this
"глобальный объект", который в браузере является окном
function foo() {
console.log(this);
}
foo(); // this is the window object
Другими словами,
foo();
был эффективно переведен на
foo.call(window);
Обратите внимание, что если вы используете строгий режим, то this
будет undefined
'use strict';
function foo() {
console.log(this);
}
foo(); // this is the window object
что значит
Другими словами,
foo();
был эффективно переведен на
foo.call(undefined);
В JavaScript есть операторы типа +
и -
и *
. Существует также точка оператора, который есть .
.
Оператор, когда используется с функцией справа и объектом слева, фактически означает "передать объект как this
функция".
пример
const bar = {
name: 'bar',
foo() {
console.log(this);
},
};
bar.foo(); // this is bar
Другими словами, bar.foo()
переводится как const temp = bar.foo; temp.call(bar);
const temp = bar.foo; temp.call(bar);
Обратите внимание, что не имеет значения, как была создана функция (в основном...). Все это даст одинаковые результаты
const bar = {
name: 'bar',
fn1() { console.log(this); },
fn2: function() { console.log(this); },
fn3: otherFunction,
};
function otherFunction() { console.log(this) };
bar.fn1(); // this is bar
bar.fn2(); // this is bar
bar.fn3(); // this is bar
Опять же, все это просто синтаксический сахар для
{ const temp = bar.fn1; temp.call(bar); }
{ const temp = bar.fn2; temp.call(bar); }
{ const temp = bar.fn3; temp.call(bar); }
Еще одна морщина - это прототип цепи. Когда вы используете ab
JavaScript сначала просматривает объект, на который ссылается a
для свойства b
. Если b
не найден в объекте, тогда JavaScript будет искать в прототипе объекта, чтобы найти b
.
Существуют различные способы определения прототипа объекта, наиболее распространенным в 2019 году является ключевое слово class
. Для целей this
хотя это не имеет значения. Имеет значение то, что, когда он смотрит на объект a
для свойства b
если он находит свойство b
в объекте или в цепочке прототипов, если b
оказывается функцией, то применяются те же правила, что и выше. Ссылки на функцию b
будут вызываться с использованием метода call
и передачи a
качестве objectForThis, как показано в верхней части этого ответа.
Сейчас. Давайте представим, что мы создаем функцию, которая явно устанавливает this
перед вызовом другой функции, а затем вызываем ее с помощью .
(точка) оператор
function foo() {
console.log(this);
}
function bar() {
const objectForThis = {name: 'moo'}
foo.call(objectForThis); // explicitly passing objectForThis
}
const obj = {
bar,
};
obj.bar();
После перевода для использования call
obj.bar()
становится const temp = obj.bar; temp.call(obj);
const temp = obj.bar; temp.call(obj);
, Когда мы входим в функцию bar
мы вызываем foo
но мы явно передаем другой объект для objectForThis, поэтому, когда мы приходим к foo, this
тот самый внутренний объект.
Это то, что эффективно выполняют функции bind
и =>
. Они более синтаксические сахара. Они эффективно создают новую невидимую функцию в точности как вышеупомянутая bar
которая явно устанавливает this
прежде чем она вызовет любую указанную функцию. В случае связывания this
установлено на то, что вы передаете bind
.
function foo() {
console.log(this);
}
const bar = foo.bind({name: 'moo'});
// bind created a new invisible function that calls foo with the bound object.
bar();
// the objectForThis we are passing to bar here is ignored because
// the invisible function that bind created will call foo with with
// the object we bound above
bar.call({name: 'other'});
Обратите внимание, что если functionObject.bind
не существует, мы можем сделать наш собственный вот так
function bind(fn, objectForThis) {
return function(...args) {
return fn.call(objectForthis, ...args);
};
}
и тогда мы могли бы назвать это так
function foo() {
console.log(this);
}
const bar = bind(foo, {name:'abc'});
Функции стрелок, оператор =>
являются синтаксическим сахаром для привязки
const a = () => {console.log(this)};
такой же как
const tempFn = function() {console.log(this)};
const a = tempFn.bind(this);
Точно так же, как bind
, создается новая невидимая функция, которая вызывает данную функцию со связанным значением для objectForThis
но в отличие от bind
объект, который должен быть связан, является неявным. Как бы this
ни было, когда используется оператор =>
.
Так же, как и правила выше
const a = () => { console.log(this); } // this is the global object
'use strict';
const a = () => { console.log(this); } // this is undefined
function foo() {
return () => { console.log(this); }
}
const obj = {
foo,
};
const b = obj.foo();
b();
obj.foo()
переводится как const temp = obj.foo; temp.call(obj);
const temp = obj.foo; temp.call(obj);
Это означает, что оператор стрелки внутри foo
свяжет obj
с новой невидимой функцией и вернет ту новую невидимую функцию, которая назначена b
. b()
будет работать, как всегда, как b.call(window)
или b.call(undefined)
вызывая новую невидимую функцию, созданную foo
. Эта невидимая функция игнорирует this
переданный в нее, и передает obj
как objectForThis 'в функцию стрелки.
Код выше переводится как
function foo() {
function tempFn() {
console.log(this);
}
return tempFn.bind(this);
}
const obj = {
foo,
};
const b = obj.foo();
b.call(window or undefined if strict mode);
1apply
это еще одна функция, похожая на call
functionName.apply(objectForThis, arrayOfArgs);
Но с ES6 концептуально вы можете даже перевести это на
functionName.call(objectForThis, ...arrayOfArgs);
this
Javascript:this
определяется тем, как функция вызывается не, где она была создана!this
определяется Объектом, который остается от точки. (window
в глобальном пространстве)this
относится к элементу DOM, на котором было названо событие.new
значение this
относится к вновь созданному объектуthis
с помощью функций: call
, apply
, bind
let object = {
prop1: function () {console.log(this);}
}
object.prop1(); // object is left of the dot, thus this is object
const myFunction = object.prop1 // We store the function in the variable myFunction
myFunction(); // Here we are in the global space
// myFunction is a property on the global object
// Therefore it logs the window object
document.querySelector('.foo').addEventListener('click', function () {
console.log(this); // This refers to the DOM element the eventListener was invoked from
})
document.querySelector('.foo').addEventListener('click', () => {
console.log(this); // Tip, es6 arrow function don't have their own binding to the this v
}) // Therefore this will log the global object
.foo:hover {
color: red;
cursor: pointer;
}
<div class="foo">click me</div>
function Person (name) {
this.name = name;
}
const me = new Person('Willem');
// When using the new keyword the this in the constructor function will refer to the newly created object
console.log(me.name);
// Therefore, the name property was placed on the object created with new keyword.
Простой ответ:
Это ключевое слово всегда зависит от контекста вызова. Они упомянуты ниже.
ФУНКЦИЯ ВЫЗЫВАЕТСЯ С НОВЫМ КЛЮЧОМ
Если функция вызывается с ключевым словом NEW, тогда THIS будет привязан к вновь созданному объекту.
function Car(){
this.name="BMW";
}
const myCar=new Car();
myCar.name; // output "BMW"
В приведенном выше примере это будет связано с объектом 'myCar'
ФУНКЦИЯ ВЫЗЫВАЕТСЯ ТОЛЬКО С ИСПОЛЬЗОВАНИЕМ МЕТОДОВ ВЫЗОВА И ПРИМЕНЕНИЯ.
В этом случае ЭТО будет связано с объектом, который явно передается функции.
var obj1={"name":"bond"};
function printMessage(msg){
return msg+" "+this.name;
}
const message=printMessage.call(obj1,"my name is ");
console.log(message); //HERE THIS WILL BE BOUND TO obj1 WHICH WE PASSED EXPLICITLY. SAME FOR APPLY METHOD ALSO.
ЕСЛИ ФУНКЦИЯ ВЫЗЫВАЕТСЯ С ОБЪЕКТОМ, НЕПРАВИЛЬНО, ТОГДА ЭТО БУДЕТ СВЯЗАНО С ЭТИМ ОБЪЕКТОМ
var obj1={
"name":"bond",
getName: function () {
return this.name;
}
};
const newname=obj1.getName();
console.log(newname); //HERE THIS WILL BE BOUND TO obj1(WHITCHEVER OBJECT IS MENTIONED BEFORE THE DOT THIS WILL BE BOUND TO THAT)
КОГДА ФУНКЦИЯ ВЫЗЫВАЕТСЯ БЕЗ ЛЮБОГО КОНТЕКСТА, ЭТО БУДЕТ СВЯЗАНО С ГЛОБАЛЬНЫМ ОБЪЕКТОМ
const util = {
name: 'Utility',
getName: function () {
return this.name;
};
const getName=util.getName;
const newName=getName();
console.log(newName); // IF THIS EXECUTED IN BROWSER THIS WILL BE BOUND TO WINDOW OBJECT. IF THIS EXECUTED IN SERVER THIS WILL BE BOUND TO GLOBAL OBJECT
В строгом режиме это будет не определено
function setName(name){
"use strict"
return this.name;
}
setName(); //WILL BE ERROR SAYING name IS UNDEFINED.
}
в пункте 4
"this" - все о сфере видимости. Каждая функция имеет свой собственный объем, и поскольку все в JS является объектом, даже функция может хранить некоторые значения в себе с помощью "this".
$('#a').click(function(){
console.log($(this).attr('href'));
});