Как работает ключевое слово "this"?

Я заметил, что, похоже, нет четкого объяснения того, что такое ключевое слово this и как оно правильно (и неправильно) используется в JavaScript.

Я наблюдал за этим очень странное поведение и не понял, почему это произошло.

Как работает this и когда он должен использоваться?

Ответы

Ответ 1

Я рекомендую сначала прочитать статью Майка Уэста Scope на JavaScript (зеркало). Это отличное, дружественное введение в концепции 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(...); var indirectEval = eval; indirectEval(...); это косвенный вызов eval(). Смотрите ответ chuckj на (1, eval) ('this') против eval ('this') в JavaScript? и Дмитрий Сошниковых ECMA-262-5 в деталях. Глава 2. Строгий режим. когда вы можете использовать косвенный вызов eval().

Ввод кода функции

Это происходит при вызове функции. Если функция вызывается для объекта, например, в obj.myMethod() или эквивалентном obj["myMethod"](), тогда ThisBinding устанавливается на объект (obj в примере; §13.2.1). В большинстве других случаев ThisBinding устанавливается на глобальный объект (§10.4.3).

Причина написания "в большинстве других случаев" заключается в том, что существует восемь встроенных функций ECMAScript 5, которые позволяют указывать ThisBinding в списке аргументов. Эти специальные функции принимают так называемый thisArg который становится ThisBinding при вызове функции (§10.4.3).

Эти специальные встроенные функции:

  • Function.prototype.apply( thisArg, argArray )
  • Function.prototype.call( thisArg [, arg1 [, arg2,... ] ] )
  • Function.prototype.bind( thisArg [, arg1 [, arg2,... ] ] )
  • Array.prototype.every( callbackfn [, thisArg ] )
  • Array.prototype.some( callbackfn [, thisArg ] )
  • Array.prototype.forEach( callbackfn [, thisArg ] )
  • Array.prototype.map( callbackfn [, thisArg ] )
  • Array.prototype.filter( callbackfn [, thisArg ] )

В случае Function.prototype они вызываются для объекта функции, но вместо установки ThisBinding для объекта функции ThisBinding устанавливается в thisArg.

В случае функций Array.prototype данный callbackfn вызывается в контексте выполнения, где ThisBinding установлен в thisArg если он предоставлен; в противном случае, к глобальному объекту.

Это правила для простого JavaScript. Когда вы начинаете использовать библиотеки JavaScript (например, jQuery), вы можете обнаружить, что некоторые библиотечные функции манипулируют значением this. Разработчики этих библиотек JavaScript делают это, потому что это имеет тенденцию поддерживать наиболее распространенные сценарии использования, и пользователи библиотеки обычно считают такое поведение более удобным. При передаче функций обратного вызова, ссылающихся на this библиотечным функциям, вы должны ссылаться на документацию для любых гарантий того, каково значение this при вызове функции.

Если вам интересно, как библиотека JavaScript манипулирует значением this, библиотека просто использует одну из встроенных функций JavaScript, принимающих thisArg. Вы также можете написать свою собственную функцию с функцией обратного вызова и thisArg:

function doWork(callbackfn, thisArg) {
    //...
    if (callbackfn != null) callbackfn.call(thisArg);
}

Это особый случай, о котором я еще не упомянул. При создании нового объекта с помощью оператора new интерпретатор JavaScript создает новый пустой объект, устанавливает некоторые внутренние свойства и затем вызывает функцию конструктора для нового объекта. Таким образом, когда функция вызывается в контексте конструктора, значением this является новый объект, созданный интерпретатором:

function MyType() {
    this.someData = "a string";
}

var instance = new MyType();
// Kind of like the following, but there are more steps involved:
// var instance = {};
// MyType.call(instance);

Функции стрелок

Функции стрелок (введенные в ECMA6) изменяют объем this. См. Существующий канонический вопрос: функция Arrow против объявления/выражений функции: являются ли они эквивалентными/заменяемыми? для дополнительной информации. Но вкратце:

Функции стрелки не имеют свои собственные this.... переплета. Вместо этого эти идентификаторы разрешаются в лексической области, как и любая другая переменная. Это означает, что внутри функции стрелки this... ссылается на значения this в среде, в которой определена функция стрелки.

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

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

  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);
      

Ответ 2

Ключевое слово 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.
  • Также в подходе буквального объекта мы можем явно добавить членов к уже определенному объекту, используя оператор точки. Это добавляется только к конкретному экземпляру. Однако я добавил переменную в прототип функции, чтобы она отражалась во всех экземплярах функции.

Ниже я попробовал все, что мы сделали с объектом и this выше, но от первой функции создания вместо прямого написания объекта.

/********************************************************************* 
  1. When you add variable to the function using this keyword, it 
     gets added to the function prototype, thus allowing all function 
     instances to have their own copy of the variables added.
*********************************************************************/
function functionDef()
{
    this.name = "ObjDefinition";
    this.getName = function(){                
        return this+":"+this.name;
    }
}        

obj1 = new functionDef();
document.write(obj1.getName() + "<br />"); //[object Object]:ObjDefinition   

/********************************************************************* 
   2. Members explicitly added to the function protorype also behave 
      as above: all function instances have their own copy of the 
      variable added.
*********************************************************************/
functionDef.prototype.version = 1;
functionDef.prototype.getVersion = function(){
    return "v"+this.version; //see how this.version refers to the
                             //version variable added through 
                             //prototype
}
document.write(obj1.getVersion() + "<br />"); //v1

/********************************************************************* 
   3. Illustrating that the function variables added by both above 
      ways have their own copies across function instances
*********************************************************************/
functionDef.prototype.incrementVersion = function(){
    this.version = this.version + 1;
}
var obj2 = new functionDef();
document.write(obj2.getVersion() + "<br />"); //v1

obj2.incrementVersion();      //incrementing version in obj2
                              //does not affect obj1 version

document.write(obj2.getVersion() + "<br />"); //v2
document.write(obj1.getVersion() + "<br />"); //v1

/********************************************************************* 
   4. 'this' keyword refers to the immediate parent object. If you 
       nest the object through function prototype, then 'this' inside 
       object refers to the nested object not the function instance
*********************************************************************/
functionDef.prototype.nestedObj = { name: 'nestedObj', 
                                    getName1 : function(){
                                        return this+":"+this.name;
                                    }                            
                                  };

document.write(obj2.nestedObj.getName1() + "<br />"); //[object Object]:nestedObj

/********************************************************************* 
   5. If the method is on an object prototype chain, 'this' refers 
      to the object the method was called on, as if the method was on 
      the object.
*********************************************************************/
var ProtoObj = { fun: function () { return this.a } };
var obj3 = Object.create(ProtoObj); //creating an object setting ProtoObj
                                    //as its prototype
obj3.a = 999;                       //adding instance member to obj3
document.write(obj3.fun()+"<br />");//999
                                    //calling obj3.fun() makes 
                                    //ProtoObj.fun() to access obj3.a as 
                                    //if fun() is defined on obj3

4. При использовании внутри функции конструктора.

Когда функция используется в качестве конструктора (то есть когда она вызывается с new ключевым словом), this внутреннее тело функции указывает на конструируемый новый объект.

var myname = "global context";
function SimpleFun()
{
    this.myname = "simple function";
}

var obj1 = new SimpleFun(); //adds myname to obj1
//1. 'new' causes 'this' inside the SimpleFun() to point to the
//   object being constructed thus adding any member
//   created inside SimipleFun() using this.membername to the
//   object being constructed
//2. And by default 'new' makes function to return newly 
//   constructed object if no explicit return value is specified

document.write(obj1.myname); //simple function

5. При использовании внутри функции, определенной в цепочке прототипов

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

var ProtoObj = {
    fun: function () {
        return this.a;
    }
};
//Object.create() creates object with ProtoObj as its
//prototype and assigns it to obj3, thus making fun() 
//to be the method on its prototype chain

var obj3 = Object.create(ProtoObj);
obj3.a = 999;
document.write(obj3.fun()); //999

//Notice that fun() is defined on obj3 prototype but 
//'this.a' inside fun() retrieves obj3.a   

6. Внутри функций 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 внутри fun, связанным с obj1 и параметрами fun связанными с параметрами, указанными arg1, arg2, arg3,...
  • К настоящему времени разница между apply, call и bind уже стала очевидной. apply позволяет указывать аргументы для функции как массивоподобный объект, то есть объект со свойством числовой length и соответствующими неотрицательными целочисленными свойствами. В то время как call позволяет указывать аргументы функции напрямую. Как apply и call сразу 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>

8. this в функции стрелки ES6

В функции стрелки this будет вести себя как обычные переменные: оно будет унаследовано от его лексической области видимости. Функция this, в которой определена функция стрелки, будет функцией стрелки this.

Итак, то же поведение, что и:

(function(){}).bind(this)

Смотрите следующий код:

const globalArrowFunction = () => {
  return this;
};

console.log(globalArrowFunction()); //window

const contextObject = {
  method1: () => {return this},
  method2: function(){
    return () => {return this};
  }
};

console.log(contextObject.method1()); //window

const contextLessFunction = contextObject.method1;

console.log(contextLessFunction()); //window

console.log(contextObject.method2()()) //contextObject

const innerArrowFunction = contextObject.method2();

console.log(innerArrowFunction()); //contextObject 

Ответ 3

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 нигде не говорится, что такие типы функций являются фактическими функциями 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 accept, что он принимает только два параметра: 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 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 вернет саму недавно созданную функцию, готовую к call.

Дополнительные вещи, скопируйте это

Иногда вам не нравится тот факт, что 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 чтобы решить проблемы вложенной области.

Ответ 4

"this" - все о сфере видимости. Каждая функция имеет свой собственный объем, и поскольку все в JS является объектом, даже функция может хранить некоторые значения в себе, используя "this". OOP 101 учит, что "this" применим только к экземплярам объекта. Поэтому каждый раз, когда выполняется функция, новый "экземпляр" этой функции имеет новое значение "this".

Большинство людей путают, когда они пытаются использовать "this" внутри анонимных функций закрытия, например:

(function(value) {
    this.value = value;
    $('.some-elements').each(function(elt){
        elt.innerHTML = this.value;        // uh oh!! possibly undefined
    });
})(2);

Итак, внутри each(), "this" не удерживает "значение", которое вы ожидаете от него (от

this.value = value;
над ним). Итак, чтобы справиться с этой проблемой (без каламбуры), разработчик мог:
(function(value) {
    var self = this;            // small change
    self.value = value;
    $('.some-elements').each(function(elt){
        elt.innerHTML = self.value;        // phew!! == 2 
    });
})(2);

Попробуйте; вам понравится эта схема программирования

Ответ 5

this в JavaScript всегда относится к "владельцу" функции, которая выполняется.

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

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

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

element.onclick = someKindOfFunction;

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

<element onclick="someKindOfFunction()">

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

Ответ 6

Поскольку этот поток натолкнулся, я собрал несколько точек для новых читателей для темы this.

Как определяется значение this?

Мы используем это подобно тому, как мы используем местоимения в естественных языках, таких как английский: "Джон работает быстро, потому что он пытается поймать поезд". Вместо этого мы могли бы написать "... John пытается поймать поезд".

var person = {    
    firstName: "Penelope",
    lastName: "Barrymore",
    fullName: function () {

    // We use "this" just as in the sentence above:
       console.log(this.firstName + " " + this.lastName);

    // We could have also written:
       console.log(person.firstName + " " + person.lastName);
    }
}

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

Когда use strict, this в глобальном и в анонимных функциях, не связанных с каким-либо объектом, имеет значение undefined.

Ключевое слово this наиболее неправильно понято, когда: 1) мы используем метод, который использует this, 2), мы назначаем метод который использует this для переменной, 3) функция, которая использует this, передается как функция обратного вызова, а 4) this используется внутри замыкания - внутренней функции. (2)

table

Что содержит будущее

Определено в 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)


Литература:

Ответ 7

Каждый контекст выполнения в javascript имеет область контекст, который задается:

  • Как вызывается функция (в том числе как метод объекта, использование вызова и применения, использование нового)
  • Использование привязки
  • Лексически для функций стрелок (они принимают это из контекста внешнего исполнения)

Каким бы ни был этот контекст области видимости, ссылается на "this".

Вы можете изменить, что установить значение этой области , используя func.call, func.apply или func.bind.

По умолчанию, и что путает большинство новичков, когда вызывающий callback вызывается после того, как событие добавлено в элемент DOM, контекст области это значение функции является элементом DOM.

jQuery делает это тривиальным для изменения с помощью jQuery.proxy.

Ответ 8

Здесь является одним из хороших источников this в JavaScript.

Вот резюме:

  • global this

    В браузере в глобальной области this находится объект window

    <script type="text/javascript">
      console.log(this === window); // true
      var foo = "bar";
      console.log(this.foo); // "bar"
      console.log(window.foo); // "bar"
    

    В node с использованием repl, this - это верхнее пространство имен. Вы можете ссылаться на него как global.

    >this
      { ArrayBuffer: [Function: ArrayBuffer],
        Int8Array: { [Function: Int8Array] BYTES_PER_ELEMENT: 1 },
        Uint8Array: { [Function: Uint8Array] BYTES_PER_ELEMENT: 1 },
        ...
    >global === this
     true
    

    В node, выполняющемся из script, this в глобальной области запускается как пустой объект. Это не то же самое, что global

    \\test.js
    console.log(this);  \\ {}
    console.log(this === global); \\ fasle
    
  • функция this

За исключением случаев обработчиков событий DOM или когда предоставляется thisArg (см. ниже), как в node, так и в браузере с использованием this в функции, которая не вызывается с помощью new ссылок глобальный охват...

<script type="text/javascript">
    foo = "bar";

    function testThis() {
      this.foo = "foo";
    }

    console.log(this.foo); //logs "bar"
    testThis();
    console.log(this.foo); //logs "foo"
</script>

Если вы используете use strict;, в этом случае this будет undefined

<script type="text/javascript">
    foo = "bar";

    function testThis() {
      "use strict";
      this.foo = "foo";
    }

    console.log(this.foo); //logs "bar"
    testThis();  //Uncaught TypeError: Cannot set property 'foo' of undefined 
</script>

Если вы вызываете функцию с new, this будет новым контекстом, он не будет ссылаться на глобальный this.

<script type="text/javascript">
    foo = "bar";

    function testThis() {
      this.foo = "foo";
    }

    console.log(this.foo); //logs "bar"
    new testThis();
    console.log(this.foo); //logs "bar"

    console.log(new testThis().foo); //logs "foo"
</script>
  • прототип

Функции, которые вы создаете, становятся объектами функции. Они автоматически получают специальное свойство prototype, которое вы можете присвоить значениям. Когда вы создаете экземпляр, вызывая свою функцию с помощью new, вы получаете доступ к значениям, присвоенным свойству prototype. Вы получаете доступ к этим значениям с помощью this.

function Thing() {
  console.log(this.foo);
}

Thing.prototype.foo = "bar";

var thing = new Thing(); //logs "bar"
console.log(thing.foo);  //logs "bar"

Как правило, ошибочно назначать массивы или объекты на prototype. Если вы хотите, чтобы экземпляры имели свои собственные массивы, создайте их в функции, а не прототипе.

function Thing() {
    this.things = [];
}

var thing1 = new Thing();
var thing2 = new Thing();
thing1.things.push("foo");
console.log(thing1.things); //logs ["foo"]
console.log(thing2.things); //logs []
  • объект this

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

var obj = {
    foo: "bar",
    logFoo: function () {
        console.log(this.foo);
    }
};

obj.logFoo(); //logs "bar"
  • DOM event this

В обработчике событий 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

Вы можете использовать eval для доступа к this.

function Thing () {
}
Thing.prototype.foo = "bar";
Thing.prototype.logFoo = function () {
    eval("console.log(this.foo)"); //logs "bar"
}

var thing = new Thing();
thing.logFoo();
  • с этим

Вы можете использовать with, чтобы добавить this в текущую область действия, чтобы читать и записывать значения на this без прямого указания this.

function Thing () {
}
Thing.prototype.foo = "bar";
Thing.prototype.logFoo = function () {
    with (this) {
        console.log(foo);
        foo = "foo";
    }
}

var thing = new Thing();
thing.logFoo(); // logs "bar"
console.log(thing.foo); // logs "foo"
  • jQuery this

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>

Ответ 9

Даниэль, удивительное объяснение! Несколько слов по этому и хорошему списку указателя контекста выполнения this в случае обработчиков событий.

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

Для обработчиков событий: обработчики событий inline, такие как <element onclick="foo">, переопределяют любые другие обработчики, прикрепленные ранее и раньше, поэтому будьте осторожны и лучше избегайте делегирования событий внутри очереди. И благодаря Заре Алавердян, которая вдохновила меня на этот список примеров через несогласные дебаты:)

  • el.onclick = foo; // in the foo - obj
  • el.onclick = function () {this.style.color = '#fff';} // obj
  • el.onclick = function() {doSomething();} // In the doSomething - Window
  • el.addEventListener('click',foo,false) // in the foo - obj
  • el.attachEvent('onclick, function () { // this }') // window, all the compliance to IE :)
  • <button onclick="this.style.color = '#fff';"> // obj
  • <button onclick="foo"> // In the foo - window, but you can <button onclick="foo(this)">

Ответ 10

Вероятно, самая подробная и всеобъемлющая статья по this вопросу:

Нежное объяснение ключевого слова "this" в JavaScript

Идея this заключается в том, чтобы понять, что типы вызова функций имеют важное значение для установки this значения.


Когда возникают проблемы с this, не спрашивайте себя:

Откуда this взято?

но спросите себя:

Как вызывается функция?

Для функции стрелки (специальный случай прозрачности контекста) спросите себя:

Какое значение имеет this значение, когда определена функция стрелки?

Это мышление правильное, когда вы имеете дело с this и избавит вас от головной боли.

Ответ 11

Существует много путаницы в отношении того, как "this" ключевое слово интерпретируется в JavaScript. Надеюсь, эта статья заложит все, чтобы отдохнуть раз и навсегда. И многое другое. Пожалуйста, внимательно прочитайте всю статью. Будьте предупреждены, что эта статья длинная.

Независимо от контекста, в котором он используется, "this" всегда ссылается на текущий "текущий объект в Javascript. Однако то, что " текущий объект" отличается в соответствии с контекстом. Контекст может быть в точности 1 из 6 следующим образом:

  • Глобальный (т.е. вне всех функций)
  • Внутри прямой "Non Bound Function" Call (т.е. функция с не была связана вызовом functionName.bind)
  • Внутри косвенной "Не привязанной функции" Вызов через functionName.call и functionName.apply
  • Внутри функции "Связанная функция" (т.е. функция была связана, вызывая functionName.bind)
  • Пока создание объекта через "новый"
  • Внутренний обработчик событий Inline DOM

Ниже описывается каждый из этих контекстов один за другим:

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

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

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

    Внутри прямой "Non Bound Function" Call, объект, который вызываемый вызов функции становится "текущим объектом" (и, следовательно, значение "this"). Если функция вызывается без явного текущего объекта, текущий объект является либо "окном (для не строгого режима), либо undefined (для строгого режима). Любая функция (или переменная), определенная в Глобальный контекст автоматически становится свойством объекта "окна. Например, предположим, что функция определена в глобальном контексте как

    function UserDefinedFunction(){
        alert(this)
        }
    

    он становится свойством объекта window, как если бы вы определили это как

    window.UserDefinedFunction=function(){
      alert(this)
    }  
    

    В режиме "Не строгого режима" вызов/вызов этой функции непосредственно через "UserDefinedFunction()" будет автоматически вызывать/вызывать он как "window.UserDefinedFunction()" делает "окно" как "текущий объект" (и, следовательно, значение "this") в пределах "UserDefinedFunction" . Включение этой функции в "Non Strict Mode" будет приведет к следующему

    UserDefinedFunction() // displays [object Window]  as it automatically gets invoked as window.UserDefinedFunction()
    

    В "Строгий режим", вызов/вызов функции непосредственно через "UserDefinedFunction()" будет "NOT" автоматически вызывать/вызывать его как "window.UserDefinedFunction()" .Сохранить текущий объект " (и значение "this") в пределах "UserDefinedFunction" должен быть undefined. Вызов этой функции в "Строгий режим" приведет к следующему

    UserDefinedFunction() // displays undefined
    

    Однако, ссылаясь на явное использование окна-объекта, следующие

    window.UserDefinedFunction() // "always displays [object Window]   irrespective of mode."
    

    Посмотрим на другой пример. Посмотрите следующий код

     function UserDefinedFunction()
        {
            alert(this.a + ","  + this.b + ","  + this.c  + ","  + this.d)
        }
    
    var o1={
                a:1,
                b:2,
                f:UserDefinedFunction
          }
    var o2={
                c:3,
                d:4,
                f:UserDefinedFunction
           }
    
    o1.f() // Shall display 1,2,undefined,undefined
    o2.f() // Shall display undefined,undefined,3,4
    

    В приведенном выше примере мы видим, что когда "UserDefinedFunction" вызывается с помощью o1, "this" принимает значение o1, а значение его свойств "a" и "b" . Значение "c" и "d" были показаны как undefined как o1. не определять эти свойства

    Аналогично, когда "UserDefinedFunction" вызывается через o2 "this" принимает значение o2, а значение его свойств "c" и "d" отображается Значение "a" и "b" было показано как undefined, поскольку o2 не определяет эти свойства.

  • Внутри косвенной "Не привязанной функции" Вызов через functionName.callи functionName.apply:

    Когда "Non Bound Function" вызывается через functionName.call или functionName.apply, "текущий объект (и, следовательно, значение "this") устанавливается на значение "this" (первый параметр) передается call/apply. Следующий код демонстрирует то же самое.

    function UserDefinedFunction()
    {
        alert(this.a + ","  + this.b + ","  + this.c  + ","  + this.d)
    }
    var o1={
                a:1,
                b:2,
                f:UserDefinedFunction
           }
    var o2={
                c:3,
                d:4,
                f:UserDefinedFunction
           }
    
    UserDefinedFunction.call(o1) // Shall display 1,2,undefined,undefined
    UserDefinedFunction.apply(o1) // Shall display 1,2,undefined,undefined
    
    UserDefinedFunction.call(o2) // Shall display undefined,undefined,3,4
    UserDefinedFunction.apply(o2) // Shall display undefined,undefined,3,4
    
    o1.f.call(o2) // Shall display undefined,undefined,3,4
    o1.f.apply(o2) // Shall display undefined,undefined,3,4
    
    o2.f.call(o1) // Shall display 1,2,undefined,undefined
    o2.f.apply(o1) // Shall display 1,2,undefined,undefined
    

    В приведенном выше коде ясно, что значение "this" для любого "NON Связанная функция "может быть изменена с помощью вызова/применения. Кроме того, если "this" не передается явно в вызов/применение, "текущий объект (и, следовательно, значение "this") установлен в "окно" в нестрочном режиме и "undefined" в строгом режиме.

  • Внутри функции "Связанная функция" (т.е. функция, связанная вызовом functionName.bind):

    Связанная функция - это функция, значение которой "this" исправлено. Следующий код показал, как работает "this" в случае связанной функции

    function UserDefinedFunction()
    {
        alert(this.a + ","  + this.b + ","  + this.c  + ","  + this.d)
    }
    var o1={
              a:1,
              b:2,
              f:UserDefinedFunction,
              bf:null
           }
    var o2={
               c:3,
               d:4,
               f:UserDefinedFunction,
               bf:null
            }
    
    var bound1=UserDefinedFunction.bind(o1); // permanantly fixes "this" value of function "bound1" to Object o1
    bound1() // Shall display 1,2,undefined,undefined
    
    var bound2=UserDefinedFunction.bind(o2); // permanantly fixes "this" value of function "bound2" to Object o2
    bound2() // Shall display undefined,undefined,3,4
    
    var bound3=o1.f.bind(o2); // permanantly fixes "this" value of function "bound3" to Object o2
    bound3() // Shall display undefined,undefined,3,4
    
    var bound4=o2.f.bind(o1); // permanantly fixes "this" value of function "bound4" to Object o1
    bound4() // Shall display 1,2,undefined,undefined
    
    o1.bf=UserDefinedFunction.bind(o2) // permanantly fixes "this" value of function "o1.bf" to Object o2
    o1.bf() // Shall display undefined,undefined,3,4
    
    o2.bf=UserDefinedFunction.bind(o1) // permanantly fixes "this" value of function "o2.bf" to Object o1
    o2.bf() // Shall display 1,2,undefined,undefined
    
    bound1.call(o2) // Shall still display 1,2,undefined,undefined. "call" cannot alter the value of "this" for bound function
    
    bound1.apply(o2) // Shall still display 1,2,undefined,undefined. "apply" cannot alter the value of "this" for bound function
    
    o2.bf.call(o2) // Shall still display 1,2,undefined,undefined. "call" cannot alter the value of "this" for bound function
    o2.bf.apply(o2) // Shall still display 1,2,undefined,undefined."apply" cannot alter the value of "this" for bound function
    

    Как указано в приведенном выше коде, значение "this" для любой "Связанной функции" НЕ МОЖЕТ быть изменен с помощью вызова/применения. Кроме того, если "this" параметр явно не передан для привязки, "текущий объект" (и, следовательно, значение "this") установлено в "окно" в Non строгий режим и "undefined" в строгом режиме. Еще кое-что. Привязка уже связанной функции не изменяет значение "this". Он остается установленным как значение, заданное первой функцией связывания.

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

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

  • Внутренний обработчик событий Inline DOM:

    Посмотрите на следующий фрагмент HTML

    <button onclick='this.style.color=white'>Hello World</button>
    <div style='width:100px;height:100px;' onclick='OnDivClick(event,this)'>Hello World</div>
    

    "this" в приведенных выше примерах относится к элементу "button", а "div" соответственно.

    В первом примере цвет шрифта кнопки должен быть установлен на белый при нажатии.

    Во втором примере, когда щелкнут элемент "div" , он должен вызовите функцию OnDivClick со своим вторым параметром ссылаясь на элемент с щелчком div. Однако значение "this" в OnDivClick НЕ ДОЛЖЕН ссылаться на нажатый div элемент. Он должен быть установлен как "оконный объект или "undefined" в Нестандартных и Строгих моделях соответственно (если OnDivClick является несвязанной функцией) или установите для предопределенного Связанное значение (если OnDivClick является связанной функцией)

Ниже приведена вся статья

  • В глобальном контексте "this" всегда ссылается на "окно

  • Всякий раз, когда вызывается функция, она вызывается в контексте object ("текущий объект). Если текущий объект явно не указан, текущий объект - это "оконный объект в NON Strict Mode и "undefined" в строгом режиме по умолчанию.

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

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

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

  • Связывание и уже связанная функция не изменяет значение "this". Он остается установленным как значение, заданное первой функцией связывания.

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

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

Ответ 12

Это лучшее объяснение, которое я видел: понять JavaScripts это с Clarity

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

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

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

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

Ответ 13

Трудно получить хорошее представление о JS или написать больше, чем что-либо тривиальное в нем, если вы не понимаете его полностью. Вы не можете просто позволить себе быстро окунуться :) Я думаю, что лучший способ начать работу с JS - сначала посмотреть эти видео-лекции Дугласа Крокфорда - http://yuiblog.com/crockford/, который охватывает это и то, и все остальное о JS.

Ответ 14

В псевдоклассических терминах многие лекции обучают ключевому слову '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;

Ответ 15

this - одна из неправильно понятых концепций в JavaScript, потому что она ведет себя немного иначе, чем место. Просто this относится к "владельцу" функции, которую мы сейчас выполняем.

this помогает получить текущий объект (контекст выполнения a.k.a.), с которым мы работаем. Если вы понимаете, в каком объекте выполняется текущая функция, вы можете легко понять, что текущий this

var val = "window.val"

var obj = {
    val: "obj.val",
    innerMethod: function () {
        var val = "obj.val.inner",
            func = function () {
                var self = this;
                return self.val;
            };

        return func;
    },
    outerMethod: function(){
        return this.val;
    }
};

//This actually gets executed inside window object 
console.log(obj.innerMethod()()); //returns window.val

//Breakdown in to 2 lines explains this in detail
var _inn = obj.innerMethod();
console.log(_inn()); //returns window.val

console.log(obj.outerMethod()); //returns obj.val

Выше мы создаем 3 переменные с одинаковым именем "val". Один в глобальном контексте, один внутри obj и другой внутри innerMethod obj. JavaScript разрешает идентификаторы в определенном контексте, поднимая цепочку областей действия из локального глобального.


Несколько мест, где this можно дифференцировать

Вызов метода объекта

var status = 1;
var helper = {
    status : 2,
    getStatus: function () {
        return this.status;
    }
};

var theStatus1 = helper.getStatus(); //line1
console.log(theStatus1); //2

var theStatus2 = helper.getStatus;
console.log(theStatus2()); //1

Когда выполняется строка1, JavaScript устанавливает контекст выполнения (EC) для вызова функции, устанавливая this объекту , на который ссылается все, что было до последнего ".. поэтому в последней строке вы можете понять, что a() был выполнен в глобальном контексте, который является window.

С конструктором

this может использоваться для ссылки на создаваемый объект

function Person(name){
    this.personName = name;
    this.sayHello = function(){
        return "Hello " + this.personName;
    }
}

var person1 = new Person('Scott');
console.log(person1.sayHello()); //Hello Scott

var person2 = new Person('Hugh');
var sayHelloP2 = person2.sayHello;
console.log(sayHelloP2()); //Hello undefined

Когда выполняется новый Person(), создается совершенно новый объект. Person вызывается, а его this устанавливается для ссылки на этот новый объект.

Вызов функции

function testFunc() {
    this.name = "Name";
    this.myCustomAttribute = "Custom Attribute";
    return this;
}

var whatIsThis = testFunc();
console.log(whatIsThis); //window

var whatIsThis2 = new testFunc();
console.log(whatIsThis2);  //testFunc() / object

console.log(window.myCustomAttribute); //Custom Attribute 

Если мы пропустим ключевое слово new, whatIsThis ссылается на самый глобальный контекст, он может найти (window)

С обработчиками событий

Если обработчик события inline, this относится к глобальному объекту

<script type="application/javascript">
    function click_handler() {
        alert(this); // alerts the window object
    }
</script>

<button id='thebutton' onclick='click_handler()'>Click me!</button>

При добавлении обработчика событий через JavaScript this относится к элементу DOM, который сгенерировал событие.


Ответ 16

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

Таким образом, семантика "this" отличается от традиционных языков ООП. И это вызывает проблемы: 1. когда функция передается другой переменной (скорее всего, обратный вызов); и 2. когда замыкание вызывается из метода-члена класса.

В обоих случаях это устанавливается как окно.

Ответ 17

Может ли this помочь? (Большая часть путаницы 'this' в javascript исходит из того факта, что она вообще не связана с вашим объектом, а с текущей исполняемой областью - это может быть не совсем так, как это работает, но мне всегда кажется, см. статью для полного объяснения)

Ответ 18

Немного информации об этом ключевом слове

Позвольте записывать this ключевое слово в консоль в глобальной области без какого-либо кода, но

console.log(this)

В Client/Browser this ключевое слово - глобальный объект, который является window

console.log(this === window) // true

а также

В среде выполнения Server/Node/Javascript this ключевое слово также является глобальным объектом, который является module.exports

console.log(this === module.exports) // true
console.log(this === exports) // true

Имейте в виду, что exports - это просто ссылка на module.exports

Ответ 19

это использование для области видимости как это

  <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') - это тот же

Ответ 20

У меня есть другое мнение об this из других ответов, которые, я надеюсь, будут полезны.

Один из способов взглянуть на JavaScript - это увидеть только 1 способ вызова функции 1. это

functionObject.call(objectForThis, arg0, arg1, arg2, ...);

Для objectForThis всегда objectForThis какое-то значение.

Все остальное является синтаксическим сахаром для functionObject.call

Итак, все остальное можно описать тем, как оно переводится в functionObject.call.

Если вы просто вызываете функцию, то this "глобальный объект", который в браузере является окном

function foo() {
  console.log(this);
}

foo();  // this is the window object

Ответ 21

Резюме 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
              
             

Ответ 22

Что такое ключевое слово "this" в JavaScript

Это ключевое слово относится к объекту, тому объекту, который выполняет текущий бит кода JavaScript.

Другими словами, каждая функция javascript во время выполнения имеет ссылку на свой текущий контекст выполнения, называемый this. Контекст выполнения означает, что здесь так называется функция.

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

function bike() {
  console.log(this.name);
}

var name = "Ninja";
var obj1 = { name: "Pulsar", bike: bike };
var obj2 = { name: "Gixxer", bike: bike };

bike();           // "Ninja"
obj1.bike();      // "Pulsar"
obj2.bike();      // "Gixxer"

В приведенном выше фрагменте кода функция job bike() печатает this.name что означает попытку печати свойства name текущего контекста выполнения (iethis object).

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

В случае вызова obj1().bike() печатается "Pulsar", и причина этого заключается в том, что функция bike() вызывается с контекстом выполнения как obj1 поэтому this.name становится obj1.name. То же самое с obj2.bike() где контекст выполнения функции bike() - obj2.

По умолчанию и неявное связывание "это"

Если мы находимся в строгом режиме, то значение этого ключевого слова по умолчанию не определено, в противном случае это ключевое слово действует как глобальный объект, так называемое связывание этого ключевого слова по умолчанию. (по умолчанию это оконный объект в случае браузера).

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

var obj1 = {
  name: "Pulsar",
  bike: function() {
    console.log(this.name);
  }
}
var obj2 = { name: "Gixxer", bike: obj1.bike };
var name = "Ninja";
var bike = obj1.bike;

bike();           // "Ninja"
obj1.bike();      // "Pulsar"
obj2.bike();      // "Gixxer"

В приведенном выше фрагменте кода вызов функции bike() является примером привязки по умолчанию. obj1.bike() и obj2.bike() являются примерами неявного связывания. Здесь велосипедная функция объявляется как часть obj1 но независимо от того, когда мы executeobj2.bike(), контекст выполнения имеет вид obj2 поэтому obj2.name.

Важно знать, как, когда и откуда вызывается функция, не имеет значения, где объявлена функция.

Явное и фиксированное связывание ключевого слова this

Если мы используем метод call и apply с вызывающей функцией, оба эти метода принимают в качестве первого параметра в качестве контекста выполнения. это то, что связывает.

function bike() {
  console.log(this.name);
}

var name = "Ninja";
var obj = { name: "Pulsar" }

bike();           // "Ninja"
bike.call(obj);   // "Pulsar"

В этом фрагменте выше, если мы вызываем функцию bike с методом call() передавая объект контекста выполнения obj в качестве первого аргумента, тогда obj присваивается этому объекту и печатает "Pulsar", который является ничем иным, как obj.name. Это называется явной привязкой этого ключевого слова.

В фиксированной или жесткой привязке

мы можем заставить этот объект всегда быть одинаковым независимо от того, откуда и как он вызывается.

var bike = function() {
  console.log(this.name);
}
var name = "Ninja";
var obj1 = { name: "Pulsar" };
var obj2 = { name: "Gixxer" };

var originalBikeFun = bike;
bike = function() {
  originalBikeFun.call(obj1);
};

bike();           // "Pulsar"
bike.call(obj2);  // "Pulsar"

В соответствии с приведенным выше фрагментом кода, bike() и bike.call(obj2) вызывают вызов "Pulsar", который является ничем иным, как obj1.name означает, что контекст выполнения функции bike всегда obj1 и это происходит из-за originalBikeFun.call(obj1); Такого рода эта привязка является просто еще одним вариантом явного связывания, называемого фиксированным связыванием.

Ответ 23

this ключевое слово относится к его текущему окружению

Ответ 24

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

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

  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. 
    

Ответ 25

"this" - все о сфере видимости. Каждая функция имеет свой собственный объем, и поскольку все в JS является объектом, даже функция может хранить некоторые значения в себе с помощью "this".

$('#a').click(function(){
console.log($(this).attr('href'));
});