Как работает ключевое слово "this"?
Я заметил, что нет четкого объяснения того, что this
Ключевое слово и как оно правильно (и неправильно) используется в JavaScript на сайте переполнения стека.
Я был свидетелем очень странного поведения с ним и не смог понять, почему это произошло.
Как this
работать и когда его следует использовать?
24 ответа
Я рекомендую сначала прочитать статью Майка Уэста " Scope in JavaScript ( mirror)". Это отличное, дружеское введение в понятия this
и области видимости в JavaScript.
Как только вы начинаете привыкать this
Правила на самом деле довольно просты. Стандарт ECMAScript 5.1 определяет this
:
§11.1.1
this
ключевое слово
this
Ключевое слово соответствует значению ThisBinding текущего контекста выполнения.
ThisBinding - это то, что поддерживает интерпретатор JavaScript при оценке кода JavaScript, например, специальный регистр ЦП, который содержит ссылку на объект. Интерпретатор обновляет ThisBinding каждый раз, когда устанавливает контекст выполнения только в одном из трех разных случаев:
1. Начальный глобальный контекст выполнения
Это имеет место для кода 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(...);
это косвенный вызов eval()
, Смотрите ответ Чака на (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
, См. Существующий канонический вопрос: функция Arr ow против объявления / выражений функции: являются ли они эквивалентными / заменяемыми? для дополнительной информации. Но вкратце:
Функции стрелок не имеют своих
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's 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's prototype but
//`this.a` inside fun() retrieves obj3.a
6. Внутри функций call(), 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
внутри весело связано с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
, - Такое же поведение выше достигается, когда мы присоединяем функцию к обработчику событий, используя метод модели регистрации событий Microsoft
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>
в JavaScript this
Простой вызов функции
Рассмотрим следующую функцию:
function foo() {
console.log("bar");
console.log(this);
}
foo(); // calling the function
Обратите внимание, что мы запускаем это в обычном режиме, то есть строгий режим не используется.
При запуске в браузере значение this
будет зарегистрирован как window
, Это потому что window
является глобальной переменной в области видимости веб-браузера.
Если вы запустите этот же кусок кода в среде, такой как node.js, this
будет ссылаться на глобальную переменную в вашем приложении.
Теперь, если мы запустим это в строгом режиме, добавив оператор "use strict";
к началу объявления функции, this
больше не будет ссылаться на глобальную переменную в любом из окружений. Это сделано, чтобы избежать путаницы в строгом режиме. this
будет, в этом случае просто войти undefined
потому что это то, что есть, оно не определено.
В следующих случаях мы увидим, как манипулировать значением this
,
Вызов функции на объекте
Есть разные способы сделать это. Если вы вызвали нативные методы в Javascript, как forEach
а также slice
, вы уже должны знать, что this
переменная в этом случае относится к Object
на котором вы вызвали эту функцию (обратите внимание, что в JavaScript почти все Object
, в том числе Array
с и Function
с). Возьмите следующий код для примера.
var myObj = {key: "Obj"};
myObj.logThis = function () {
// I am a method
console.log(this);
}
myObj.logThis(); // myObj is logged
Если Object
содержит свойство, которое содержит 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
будет назначен прототипPerson.prototype
, Это означает, что любой метод или свойство вPerson
прототип будет доступен для всех случаевPerson
, в том числеawal
, - Функция
Person
сам теперь вызывается;this
являясь ссылкой на недавно построенный объектawal
,
Довольно просто, а?
Обратите внимание, что в официальной спецификации ECMAScript no where указано, что такие типы функций актуальны 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
установленный методом вызова точки мы обсуждали во втором пункте. Достаточно просто:)
Представляя.... 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
по умолчанию? - Что если мы вызовем функцию как метод с нотацией Object-dot?
- Что делать, если мы используем
new
ключевое слово? - Как мы манипулируем
this
сcall
а такжеapply
? - С помощью
bind
, - копирование
this
решить проблемы вложенной области.
"это" все о сфере. Каждая функция имеет свою область видимости, и поскольку все в JS является объектом, даже функция может сохранять в себе некоторые значения, используя "this". ООП 101 учит, что "это" применимо только к экземплярам объекта. Следовательно, каждый раз, когда функция выполняется, новый "экземпляр" этой функции имеет новое значение "this".
Большинство людей смущаются, когда пытаются использовать "this" внутри анонимных функций закрытия, таких как:
(функция (значение) { this.value = значение; $(". Некоторые-элементы). Каждая (функция (ELT){ elt.innerHTML = this.value; // э-э-э! возможно неопределенный }); })(2);
Так что здесь, внутри each(), "this" не содержит "значение", которого вы ожидаете (от
this.value = значение;над ним). Итак, чтобы преодолеть эту (не каламбур) проблему, разработчик может:
(функция (значение) { var self = this; // небольшой изменение self.value = значение; $(". Некоторые-элементы). Каждая (функция (ELT){ elt.innerHTML = self.value; // фу!! == 2 }); })(2);
Попробуйте это; вы начнете любить эту модель программирования
Поскольку эта тема увеличилась, я собрал несколько пунктов для новых читателей this
тема.
Какова стоимость this
определяется?
Мы используем это подобно тому, как мы используем местоимения на естественных языках, таких как английский: "Джон бежит быстро, потому что он пытается успеть на поезд". Вместо этого мы могли бы написать "… Джон пытается успеть на поезд".
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)
Рекомендации:
- Это и Объектные Прототипы, Кайл Симпсон. © 2014 Getify Solutions.
- javascriptissexy.com - http://goo.gl/pvl0GX
- Ангус Кролл - http://goo.gl/Z2RacU
this
в Javascript всегда ссылается на "владельца" выполняемой функции.
Если явный владелец не определен, то указывается самый верхний владелец, объект окна.
Так что если бы я сделал
function someKindOfFunction() {
this.style = 'foo';
}
element.onclick = someKindOfFunction;
this
будет относиться к элементу объекта. Но будьте осторожны, многие люди делают эту ошибку
<element onclick="someKindOfFunction()">
В последнем случае вы просто ссылаетесь на функцию, а не передаете ее элементу. Для этого, this
будет ссылаться на объект окна.
Каждый контекст выполнения функции в javascript имеет контекст контекста этого параметра, который устанавливается:
- Как вызывается функция (в том числе как метод объекта, использование call и apply, использование new)
- Использование связывания
- Лексически для функций стрелок (они принимают this из своего внешнего контекста выполнения)
Каким бы ни был контекст этой области, на него ссылается "это".
Вы можете изменить это значение этого контекста, используя func.call
, func.apply
или же func.bind
,
По умолчанию, и то, что смущает большинство новичков, когда слушатель обратного вызова вызывается после того, как событие вызвано в элементе DOM, в контексте контекста это значение функции является элементом DOM.
jQuery делает это тривиальным, чтобы изменить с jQuery.proxy.
Вот один хороший источник this
в JavaScript
,
Вот резюме:
глобальный это
В браузере, в глобальном масштабе,
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
выполнение из скрипта,this
в глобальной области видимости начинается как пустой объект. Это не то же самое, чтоglobal
\\test.js console.log(this); \\ {} console.log(this === global); \\ fasle
функция это
За исключением случаев обработчиков событий DOM или когда thisArg
предоставляется (см. ниже), как в узле, так и в браузере, используя 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"
- DOM событие это
В обработчике событий 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 это
Внутри атрибутов 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 это
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
указатель контекста выполнения в случае обработчиков событий.
В двух словах this
в JavaScript указывает объект, от которого (или из контекста выполнения) которого была запущена текущая функция, и она всегда доступна только для чтения, в любом случае вы не можете установить ее (такая попытка приведет к "Неверной левой стороне в назначении") сообщение.
Для обработчиков событий: встроенные обработчики событий, такие как <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)">
Вероятно, самая подробная и всеобъемлющая статья о this
является следующим:
Нежное объяснение ключевого слова this в JavaScript
Идея позади this
понять, что типы вызова функций имеют большое значение при настройке this
значение.
Когда возникают проблемы с выявлением this
не спрашивайте себя
Где
this
взяты из?
но спросите себя:
Как вызывается функция?
Для функции стрелки (особый случай прозрачности контекста) спросите себя:
Какое значение имеет
this
где определяется функция стрелки?
Это мышление правильно при работе с this
и избавит вас от головной боли.
Существует много путаницы относительно того, как ключевое слово "this" интерпретируется в JavaScript. Надеюсь, эта статья положит конец всем раз и навсегда. И многое другое. Пожалуйста, внимательно прочитайте всю статью. Будьте предупреждены, что эта статья длинная.
Независимо от контекста, в котором он используется, "this" всегда ссылается на "текущий объект" в Javascript. Однако то, что является "текущим объектом", зависит от контекста. Контекст может быть ровно 1 из 6 следующих:
- Глобальный (т.е. вне всех функций)
- Внутри прямого вызова " Не связанная функция" (то есть функция, которая не была связана вызовом functionName.bind)
- Внутри косвенного вызова "не связанная функция" вызов через functionName.call и functionName.apply
- Внутри вызова "Связанная функция" (то есть функция, которая была связана вызовом functionName.bind)
- При создании объекта через "новый"
- Внутри встроенного обработчика событий DOM
Следующее описывает каждый из этих контекстов один за другим:
Глобальный контекст (т. Е. Вне всех функций):
За пределами всех функций (т.е. в глобальном контексте) "текущий объект" (и, следовательно, значение "this") всегда является объектом "окна" для браузеров.
Внутренний прямой вызов "Не связанная функция":
Внутри прямого вызова "Не связанная функция" объект, вызвавший вызов функции, становится "текущим объектом" (и, следовательно, значением "this"). Если функция вызывается без явного текущего объекта, текущий объект является либо "оконным" объектом (для нестрого режима), либо неопределенным (для строгого режима). Любая функция (или переменная), определенная в глобальном контексте, автоматически становится свойством объекта "окна". Например, предположим, что функция определяется в глобальном контексте как
function UserDefinedFunction(){ alert(this) }
оно становится свойством объекта окна, как если бы вы определили его как
window.UserDefinedFunction=function(){ alert(this) }
В "Не строгом режиме" вызов / вызов этой функции напрямую через "UserDefinedFunction()" автоматически вызовет / вызовет ее как "window.UserDefinedFunction()", делая "окно" "текущим объектом" (и, следовательно, значением " this ") в "UserDefinedFunction". Вызов этой функции в" не строгом режиме "приведет к следующему
UserDefinedFunction() // displays [object Window] as it automatically gets invoked as window.UserDefinedFunction()
В "Строгом режиме" вызов / вызов функции напрямую через "UserDefinedFunction()" будет "НЕ" автоматически вызывать / вызывать ее как "window.UserDefinedFunction()". Подразумевает "текущий объект" (и значение "this") внутри "UserDefinedFunction" должно быть неопределенным. Вызов этой функции в "Строгом режиме" приведет к следующему
UserDefinedFunction() // displays undefined
Однако его явный вызов с использованием объекта window должен привести к следующему
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" были показаны как неопределенные, поскольку o1 не определяет эти свойства
Аналогично, когда "UserDefinedFunction" вызывался через o2, "this" принимает значение o2, и отображаются значения его свойств "c" и "d". Значения "a" и "b" были показаны как неопределенные, как и o2 не определять эти свойства.
Внутри косвенного вызова "не связанная функция" вызов через functionName.call и functionName.apply:
Когда через функцию functionName.call или functionName.apply вызывается "Не связанная функция", "текущему объекту" (и, следовательно, значению "this") присваивается значение "this" параметра (первого параметра), передаваемого для вызова. / применить. Следующий код демонстрирует то же самое.
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 Bound Function" может быть изменено с помощью call / apply. Кроме того, если параметр "this" не передан явно в call / apply, "текущий объект" (и, следовательно, значение "this") устанавливается в "window" в нестрогом режиме и "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") устанавливается в "window" в нестрогом режиме и "undefined" в строгом режиме. Еще кое-что. Привязка уже связанной функции не меняет значение "this". Он остается установленным в качестве значения, установленного первой функцией связывания.
При создании объекта через "новый":
Внутри функции конструктора "текущий объект" (и, следовательно, значение "этого") ссылается на объект, который в данный момент создается через "новый", независимо от состояния привязки функции. Однако, если конструктор является связанной функцией, он должен вызываться с предопределенным набором аргументов, установленным для связанной функции.
Внутри встроенного обработчика событий 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. Он должен быть установлен как "оконный объект" или "неопределенный" в нестрогих и строгих режимах соответственно (если OnDivClick является несвязанной функцией) или установлен в предопределенное значение Bound (если OnDivClick является связанной функцией)
Следующее суммирует всю статью
В глобальном контексте "это" всегда относится к объекту "окна"
Всякий раз, когда вызывается функция, она вызывается в контексте объекта ("текущий объект"). Если текущий объект явно не указан, то текущий объект является "оконным объектом" в строгом режиме и не определен в строгом режиме по умолчанию.
Значение "this" в функции Non Bound является ссылкой на объект, в контексте которого вызывается функция ("текущий объект")
Значение this в функции Non Bound может быть переопределено с помощью вызова и применения методов функции.
Значение "this" является фиксированным для функции Bound и не может быть переопределено вызовом и применением методов функции.
Привязка и уже связанная функция не изменяют значение "this". Он остается установленным в качестве значения, установленного первой функцией связывания.
Значение "this" в конструкторе - это объект, который создается и инициализируется
Значение "this" в встроенном обработчике событий DOM является ссылкой на элемент, для которого предоставляется обработчик события.
Это лучшее объяснение, которое я видел. Поймите JavaScripts это с ясностью
Эта ссылка ВСЕГДА ссылается (и содержит значение) на объект - единственный объект - и обычно используется внутри функции или метода, хотя может использоваться и вне функции в глобальной области видимости. Обратите внимание, что когда мы используем строгий режим, он содержит значение undefined в глобальных функциях и в анонимных функциях, которые не связаны ни с одним объектом.
Есть четыре условия, в которых это может сбивать с толку:
- Когда мы передаем метод (который использует это) в качестве параметра, который будет использоваться в качестве функции обратного вызова.
- Другой случай, когда это неправильно понимается, - это когда мы используем внутренний метод (замыкание). Важно отметить, что замыкания не могут получить доступ к внешней переменной this- переменной с помощью ключевого слова this, потому что переменная this доступна только самой функции, а не внутренним функциям.
- Использование этого, когда метод назначен переменной. Значение this привязывается к другому объекту, если мы назначим метод, который использует это для переменной
- Использование этого при использовании связывания, применения и вызова методов.
Он приводит примеры кода, пояснения и исправления кода, которые, на мой взгляд, были очень полезны.
Значение this зависит от контекста, в котором выполняется функция. Контекст может быть любым объектом или глобальным объектом, то есть окном.
Так что Семантика "этого" отличается от традиционных языков ООП. И это вызывает проблемы: 1. когда функция передается другой переменной (скорее всего, обратному вызову); и 2. когда замыкание вызывается из метода-члена класса.
В обоих случаях это установлено в окно.
В псевдоклассических терминах, во многих лекциях учат ключевое слово "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;
this
это одна из неправильно понятых концепций в JavaScript, потому что она ведет себя немного по-разному в разных местах. Просто, this
относится к "владельцу" функции, которую мы выполняем в настоящее время.
this
помогает получить текущий объект (или контекст выполнения), с которым мы работаем. Если вы понимаете, в каком объекте выполняется текущая функция, вы можете легко понять, какая текущая функция 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 of 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
Когда line1 выполняется, 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
)
С обработчиками событий
Если обработчик события встроен, 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()
- Прокси-сервер JQuery - это еще один способ, которым вы можете использовать, чтобы убедиться, что в функции будет значение, которое вы хотите. (Проверьте понимание использования $.proxy (), jQuery.proxy ())
- Что значит
var that = this
значит в JavaScript
Трудно получить хорошее представление о JS или написать в нем больше, чем что-либо тривиальное, если вы не понимаете его полностью. Вы не можете позволить себе просто немного окунуться:) Я думаю, что лучший способ начать работу с JS - это сначала посмотреть эти видео-лекции Дугласа Крокфорда - http://yuiblog.com/crockford/, которые охватывают то и это, и все остальное о JS.
Как это может помочь? (Большая путаница с "этим" в javascript связана с тем, что он, как правило, связан не с вашим объектом, а с текущей областью выполнения - это может быть не совсем так, как это работает, но мне всегда кажется, что это так - см. статью для полного объяснения)
У меня другой взгляд на this
из других ответов, которые, я надеюсь, полезны.
Один из способов взглянуть на JavaScript - это увидеть только 1 способ вызова функции 1. это
functionObject.call(objectForThis, arg0, arg1, arg2, ...);
Всегда есть какая-то ценность для 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 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); }
Еще одна морщина - это прототип цепи. Когда вы используете a.b
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);
, Когда мы входим в 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);
что означает стрелку оператора внутри 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);
1 apply
другая функция похожа на call
functionName.apply(objectForThis, arrayOfArgs);
Но с ES6 концептуально вы можете даже перевести это на
functionName.call(objectForThis, ...arrayOfArgs);
Немного информации об этом ключевом слове
Давайте войдем this
Ключевое слово для консоли в глобальной области видимости без кода, но
console.log(this)
В клиенте / браузере this
Ключевое слово является глобальным объектом, который window
console.log(this === window) // true
а также
В среде выполнения сервера / узла /Javascript this
Ключевое слово также является глобальным объектом, который module.exports
console.log(this === module.exports) // true
console.log(this === exports) // true
Иметь ввиду exports
это просто ссылка на module.exports
"this" в JavaScript это одно из свойств контекста выполнения.
- это свойство создается каждый раз при выполнении функции, а не перед этим.
- Его значение не статично, а скорее зависит от того, как оно используется.
- принимает значение, указывающее на владельца функции, в которой оно используется
Существуют различные способы использования ключевого слова this, ниже приведены примеры для него (метод, обычная функция, стрелочная функция, прослушиватель событий, явная привязка функции).
1. Внутри метода.
this === (к объекту, вызывающему метод).
В приведенном выше примере метод «fullName()» вызывается объектом «person», поэтому значение this внутри метода «fullName()» будет равно объекту «person».
2. Внутри функции.
i) объявление/выражение функции
в свободном режиме это === окно (объект)
в строгом режиме это === undefined
Примечание. Это свойство работает одинаково при определении функции с использованием объявления функции или выражения функции.
ii) Функция стрелки:
Функция со стрелкой не имеет собственного свойства this, они принимают значение this в качестве окружающей их функции. Если функция окружения отсутствует, т.е. если они определены на глобальном уровне, то это === окно (объект)
3. Event Listener это === объект, на который привязан обработчик. привязка события щелчка к объекту документа
В приведенном выше примере, поскольку обработчик кликов прикреплен к объекту «документ», он будет равен объекту «документ».
4. Явное связывание функций (вызов, применение, связывание)
Методы call() и apply() являются предопределенными методами JavaScript.
Оба они могут использоваться для вызова метода объекта с другим объектом в качестве аргумента.
В приведенном выше примере это внутри «printFullDetails()» явно установлено для personObj1 и personObj2 путем передачи в качестве первого аргумента для вызова метода.
Вы можете узнать больше о методах вызова, применения и привязки здесь .
Резюме 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.
Это использование для Scope так же, как это
<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') равно
Чтобы правильно понять "это", нужно понимать контекст, объем и разницу между ними.
Область действия: в JavaScript область действия связана с видимостью переменных, область действия достигается за счет использования функции. (Подробнее о сфере применения)
Контекст: контекст связан с объектами. Он относится к объекту, которому принадлежит функция. Когда вы используете "это" ключевое слово JavaScript, оно относится к объекту, которому принадлежит функция. Например, внутри функции, когда вы говорите: "this.accoutNumber", вы имеете в виду свойство "accoutNumber", которое принадлежит объекту, которому принадлежит эта функция.
Если у объекта "myObj" есть метод с именем "getMyName", когда ключевое слово JavaScript "this" используется внутри "getMyName", оно относится к "myObj". Если функция "getMyName" была выполнена в глобальной области видимости, то "это" относится к объекту окна (кроме строгого режима).
Теперь посмотрим на пример:
<script>
console.log('What is this: '+this);
console.log(this);
</script>
Выполненный выше код в выводе браузера будет:
Согласно выходным данным, вы находитесь внутри контекста объекта окна, также видно, что прототип окна относится к объекту.
Теперь давайте попробуем внутри функции:
<script>
function myFunc(){
console.log('What is this: '+this);
console.log(this);
}
myFunc();
</script>
Выход:
Результат такой же, потому что мы регистрировали переменную this в глобальной области видимости и регистрировали ее в функциональной области, мы не меняли контекст. В обоих случаях контекст был одинаковым, относящимся к объекту вдовы.
Теперь создадим наш собственный объект. В javascript вы можете создать объект разными способами.
<script>
var firstName = "Nora";
var lastName = "Zaman";
var myObj = {
firstName:"Lord",
lastName:'Baron',
printNameGetContext:function(){
console.log(firstName + " "+lastName);
console.log(this.firstName +" "+this.lastName);
return this;
}
}
var context = myObj.printNameGetContext();
console.log(context);
</script>
Выход:
Итак, из приведенного выше примера мы обнаружили, что ключевое слово this относится к новому контексту, связанному с myObj, а myObject также имеет цепочку прототипов для Object.
Приведем еще один пример:
<body>
<button class="btn">Click Me</button>
<script>
function printMe(){
//Terminal2: this function declared inside window context so this function belongs to the window object.
console.log(this);
}
document.querySelector('.btn').addEventListener('click', function(){
//Terminal1: button context, this callback function belongs to DOM element
console.log(this);
printMe();
})
</script>
</body>
вывод: имеет смысл, правда? (читать комментарии)
Если у вас возникли проблемы с пониманием приведенного выше примера, давайте попробуем использовать наш собственный обратный вызов;
<script>
var myObj = {
firstName:"Lord",
lastName:'Baron',
printName:function(callback1, callback2){
//Attaching callback1 with this myObj context
this.callback1 = callback1;
this.callback1(this.firstName +" "+this.lastName)
//We did not attached callback2 with myObj so, it's reamin with window context by default
callback2();
/*
//test bellow codes
this.callback2 = callback2;
this.callback2();
*/
}
}
var callback2 = function (){
console.log(this);
}
myObj.printName(function(data){
console.log(data);
console.log(this);
}, callback2);
</script>
выход:
Теперь давайте разберемся, как себя ведет Scope, Self, IIFE и ЭТО
var color = 'red'; // property of window
var obj = {
color:'blue', // property of window
printColor: function(){ // property of obj, attached with obj
var self = this;
console.log('In printColor -- this.color: '+this.color);
console.log('In printColor -- self.color: '+self.color);
(function(){ // decleard inside of printColor but not property of object, it will executed on window context.
console.log(this)
console.log('In IIFE -- this.color: '+this.color);
console.log('In IIFE -- self.color: '+self.color);
})();
function nestedFunc(){// decleard inside of printColor but not property of object, it will executed on window context.
console.log('nested fun -- this.color: '+this.color);
console.log('nested fun -- self.color: '+self.color);
}
nestedFunc(); // executed on window context
return nestedFunc;
}
};
obj.printColor()(); // returned function executed on window context
</script>
Простой ответ:
Это ключевое слово всегда зависит от контекста вызова. Они упомянуты ниже.
ФУНКЦИЯ ВЫЗЫВАЕТСЯ С НОВЫМ КЛЮЧОМ
Если функция вызывается с ключевым словом 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.