Как работает ключевое слово "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 в среде функция стрелки определена в.

Просто для удовольствия, проверьте свое понимание с некоторыми примерами

Чтобы раскрыть ответы, наведите курсор мыши на светло-желтые прямоугольники.

  1. Какова стоимость this на отмеченной линии? Зачем?

    window - Отмеченная строка оценивается в начальном глобальном контексте выполнения.

    if (true) {
        // What is `this` here?
    }
    
  2. Какова стоимость 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);
      

  3. Какова стоимость 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);
      

  4. Какова стоимость this на отмеченной линии? Зачем?

    window

    Этот был хитрым. При оценке eval-кода this является obj, Тем не менее, в коде Eval, myFun не вызывается для объекта, поэтому ThisBinding установлен в window для вызова.

    function myFun() {
        return this; // What is `this` here?
    }
    var obj = {
        myMethod: function () {
            eval("myFun()");
        }
    };
    
  5. Какова стоимость 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 ключевое слово.

  1. Вызов функции с помощью new Ключевое слово немедленно инициализирует Object типа Person,
  2. Конструктор этого Object его конструктор установлен в Person, Также обратите внимание, что typeof awal вернется Object только.
  3. Это новый Object будет назначен прототип Person.prototype, Это означает, что любой метод или свойство в Person прототип будет доступен для всех случаев Person, в том числе awal,
  4. Функция 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, Умно, а?

Индекс:

  1. Что проводится в this по умолчанию?
  2. Что если мы вызовем функцию как метод с нотацией Object-dot?
  3. Что делать, если мы используем new ключевое слово?
  4. Как мы манипулируем this с call а также apply?
  5. С помощью bind,
  6. копирование 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)


Рекомендации:

  1. Это и Объектные Прототипы, Кайл Симпсон. © 2014 Getify Solutions.
  2. javascriptissexy.com - http://goo.gl/pvl0GX
  3. Ангус Кролл - http://goo.gl/Z2RacU

this в Javascript всегда ссылается на "владельца" выполняемой функции.

Если явный владелец не определен, то указывается самый верхний владелец, объект окна.

Так что если бы я сделал

function someKindOfFunction() {
   this.style = 'foo';
}

element.onclick = someKindOfFunction;

this будет относиться к элементу объекта. Но будьте осторожны, многие люди делают эту ошибку

<element onclick="someKindOfFunction()">

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

Каждый контекст выполнения функции в javascript имеет контекст контекста этого параметра, который устанавливается:

  1. Как вызывается функция (в том числе как метод объекта, использование call и apply, использование new)
  2. Использование связывания
  3. Лексически для функций стрелок (они принимают 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 следующих:

  1. Глобальный (т.е. вне всех функций)
  2. Внутри прямого вызова " Не связанная функция" (то есть функция, которая не была связана вызовом functionName.bind)
  3. Внутри косвенного вызова "не связанная функция" вызов через functionName.call и functionName.apply
  4. Внутри вызова "Связанная функция" (то есть функция, которая была связана вызовом functionName.bind)
  5. При создании объекта через "новый"
  6. Внутри встроенного обработчика событий DOM

Следующее описывает каждый из этих контекстов один за другим:

  1. Глобальный контекст (т. Е. Вне всех функций):

    За пределами всех функций (т.е. в глобальном контексте) "текущий объект" (и, следовательно, значение "this") всегда является объектом "окна" для браузеров.

  2. Внутренний прямой вызов "Не связанная функция":

    Внутри прямого вызова "Не связанная функция" объект, вызвавший вызов функции, становится "текущим объектом" (и, следовательно, значением "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 не определять эти свойства.

  3. Внутри косвенного вызова "не связанная функция" вызов через 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" в строгом режиме.

  4. Внутри вызова "Связанной функции" (то есть функции, которая была связана вызовом 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". Он остается установленным в качестве значения, установленного первой функцией связывания.

  5. При создании объекта через "новый":

    Внутри функции конструктора "текущий объект" (и, следовательно, значение "этого") ссылается на объект, который в данный момент создается через "новый", независимо от состояния привязки функции. Однако, если конструктор является связанной функцией, он должен вызываться с предопределенным набором аргументов, установленным для связанной функции.

  6. Внутри встроенного обработчика событий 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 является связанной функцией)

Следующее суммирует всю статью

  1. В глобальном контексте "это" всегда относится к объекту "окна"

  2. Всякий раз, когда вызывается функция, она вызывается в контексте объекта ("текущий объект"). Если текущий объект явно не указан, то текущий объект является "оконным объектом" в строгом режиме и не определен в строгом режиме по умолчанию.

  3. Значение "this" в функции Non Bound является ссылкой на объект, в контексте которого вызывается функция ("текущий объект")

  4. Значение this в функции Non Bound может быть переопределено с помощью вызова и применения методов функции.

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

  6. Привязка и уже связанная функция не изменяют значение "this". Он остается установленным в качестве значения, установленного первой функцией связывания.

  7. Значение "this" в конструкторе - это объект, который создается и инициализируется

  8. Значение "this" в встроенном обработчике событий DOM является ссылкой на элемент, для которого предоставляется обработчик события.

Это лучшее объяснение, которое я видел. Поймите JavaScripts это с ясностью

Эта ссылка ВСЕГДА ссылается (и содержит значение) на объект - единственный объект - и обычно используется внутри функции или метода, хотя может использоваться и вне функции в глобальной области видимости. Обратите внимание, что когда мы используем строгий режим, он содержит значение undefined в глобальных функциях и в анонимных функциях, которые не связаны ни с одним объектом.

Есть четыре условия, в которых это может сбивать с толку:

  1. Когда мы передаем метод (который использует это) в качестве параметра, который будет использоваться в качестве функции обратного вызова.
  2. Другой случай, когда это неправильно понимается, - это когда мы используем внутренний метод (замыкание). Важно отметить, что замыкания не могут получить доступ к внешней переменной this- переменной с помощью ключевого слова this, потому что переменная this доступна только самой функции, а не внутренним функциям.
  3. Использование этого, когда метод назначен переменной. Значение this привязывается к другому объекту, если мы назначим метод, который использует это для переменной
  4. Использование этого при использовании связывания, применения и вызова методов.

Он приводит примеры кода, пояснения и исправления кода, которые, на мой взгляд, были очень полезны.

Значение 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, который сгенерировал событие.


Трудно получить хорошее представление о 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> 

Выход довольно классный, правда?

Простой ответ:

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

  1. ФУНКЦИЯ ВЫЗЫВАЕТСЯ С НОВЫМ КЛЮЧОМ

    Если функция вызывается с ключевым словом NEW, тогда THIS будет привязан к вновь созданному объекту.

    function Car(){
      this.name="BMW";
    }
    const myCar=new Car();
    myCar.name; // output "BMW"
    

    В приведенном выше примере это будет связано с объектом 'myCar'

  2. ФУНКЦИЯ ВЫЗЫВАЕТСЯ ТОЛЬКО С ИСПОЛЬЗОВАНИЕМ МЕТОДОВ ВЫЗОВА И ПРИМЕНЕНИЯ.

    В этом случае ЭТО будет связано с объектом, который явно передается функции.

    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.
    
  3. ЕСЛИ ФУНКЦИЯ ВЫЗЫВАЕТСЯ С ОБЪЕКТОМ, НЕПРАВИЛЬНО, ТОГДА ЭТО БУДЕТ СВЯЗАНО С ЭТИМ ОБЪЕКТОМ

    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)
    
  4. КОГДА ФУНКЦИЯ ВЫЗЫВАЕТСЯ БЕЗ ЛЮБОГО КОНТЕКСТА, ЭТО БУДЕТ СВЯЗАНО С ГЛОБАЛЬНЫМ ОБЪЕКТОМ

    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
    
  5. В строгом режиме это будет не определено

    function setName(name){
        "use strict"
        return this.name;
    }
    setName(); //WILL BE ERROR SAYING name IS UNDEFINED. 
    
Другие вопросы по тегам