“ this”关键字如何工作?


1308

我注意到,对于thisStack Overflow网站上的JavaScript,关键字是什么以及如何正确(以及错误地)使用关键字似乎没有明确的解释。

我目睹了它的一些非常奇怪的行为,并且未能理解为什么会发生它。

如何this工作以及何时使用?


6
我在Google搜索“ this” quirksmode.org/js/this.html
Wai Wong,2010年


2
彼得·米修(Peter Michaux)提倡不要使用this peter.michaux.ca/articles/javascript-widgets-without-this
Marcel Korpel 2010年


Answers:


1349

我建议先阅读Mike West的文章Scope in JavaScript镜像)。这是对thisJavaScript和范围链的概念的出色而友好的介绍。

一旦开始习惯this,规则实际上就非常简单。所述的ECMAScript 5.1标准定义this

§11.1.1this关键字

所述this关键字的计算结果为当前执行上下文的ThisBinding的值

JavaScript解释器在评估JavaScript代码时会维护ThisBinding,例如特殊的CPU寄存器,其中包含对对象的引用。每当仅在以下三种情况之一中建立执行上下文时,解释器就会更新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.0.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()。见chuckj的回答(1,EVAL)( '本')与在JavaScript中的eval( '本')?Dmitry Soshnikov的ECMA-262-5详细信息。第2章严格模式。有关何时可以使用间接eval()调用的信息。

输入功能码

调用函数时会发生这种情况。如果在某个对象(例如in obj.myMethod()或等效对象)中调用了函数obj["myMethod"](),则ThisBinding设置为该对象(obj在示例中;第13.2.1节)。在大多数其他情况下,ThisBinding设置为全局对象(第10.4.3节)。

之所以写“在大多数情况下”,是因为有八个ECMAScript 5内置函数可以在参数列表中指定ThisBinding。这些特殊功能带有一个所谓的thisArg,当调用该功能时(第10.4.3节),它成为ThisBinding

这些特殊的内置函数是:

  • 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在执行上下文中调用给定,thisArg如果提供,则将ThisBinding设置为;否则,转到全局对象。

这些是纯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。参见现有的规范问题,箭头函数与函数声明/表达式:它们是否等效/可互换?欲获得更多信息。简而言之:

箭头函数没有自己的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不同,在Python中,访问method(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

    这个很棘手。评估评估代码时,thisobj。但是,在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);
      


6
@Ali:它们是对ECMAScript标准5.1版ECMA-262中的部分的引用。我提供它们,以便您可以根据需要阅读标准的技术细节。
丹尼尔·特雷比恩

1
我认为@supertonsky关于#2是正确的-如果从全局范围调用myFun(),而不是作为对象的方法,则“ this”将是全局对象,因此问题的措辞很重要。顺便说一句-我真的很喜欢使用鼠标悬停获取类似答案的想法。
user655489

2
但是,jsfiddle.net/H4LYm/2表明该setTimeout示例thiswindow(global)
凯文·梅雷迪斯

2
来自Python的人们会想象我碰到第三个示例时的沮丧程度
。.smh

1
即使更改只是术语,也应更新此答案以反映ES2020的现实。
本·阿斯顿

156

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。指定它们。
  • 对象文字表示法创建了一个对象实例,我们可以立即使用它。使用函数,我们可能首先需要使用newoperator 创建其实例。
  • 同样,在对象文字方法中,我们可以使用点运算符将成员显式添加到已定义的对象中。这仅添加到特定实例。但是,我已将变量添加到函数原型中,以使其在函数的所有实例中得到反映。

在下面,我尝试了使用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])设置obj1thisinside 的值,fun()并将fun()传递argsArray其的元素作为其参数。
  • fun.call(obj1 [, arg1 [, arg2 [,arg3 [, ...]]]])-设置obj1thisinside 的值,fun()并将fun()传递的调用arg1, arg2, arg3, ...作为其参数。
  • fun.bind(obj1 [, arg1 [, arg2 [,arg3 [, ...]]]])-返回对函数的引用,该函数funthis内部Fun绑定到obj1参数,而参数fun绑定到指定的参数arg1, arg2, arg3,...
  • 到现在applycall和之间的区别bind已经很明显了。apply允许指定参数以充当类似数组的对象,即具有数字length属性和相应的非负整数属性的对象。而call允许直接指定函数的参数。两者applycall立即在指定的上下文中使用指定的参数调用该函数。另一方面,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 

“当在全局上下文中定义的函数中使用此函数时,由于该函数实际上是全局上下文的一种方法,因此它仍然绑定到全局对象。” 是不正确的。是通过函数的调用方式或bind设置的,而不是由定义的位置设置的。呼叫没有碱参考(“上下文”)的任何功能将默认这个全局对象或在严格模式仍然不确定。
RobG

@RobG hmm可能是,但是我在MDN上发现了这种情况thisthis在这种情况下,调用未设置的值由于代码不是处于严格模式下,因此值必须始终是一个对象,因此它默认为全局对象。实际上,这就是为什么我认为我们可以直接进行call window.f1(),所以意味着在调用之前,该意思f1()已经附加到window对象上了。我搞错了吗?
Mahesha999

我是在评论(也许不是清楚)在你的设置链接与“功能实际上是由全球范围内的方法”,仿佛这有点叫window.fn,它不是。默认为全局对象,因为在呼叫中使用的函数被定义,其中的不因为没有基准参照,(所以仍然是由功能如何被调用设置)。如果你明确地把它用window.fn,那么你设置窗口。结果相同,处理方式不同。:-)
RobG

“上面我已经把这个词放在眼前了……”不,你没有。您可以对此进行修改,以解决错误吗?答案似乎是语义的,因此由于无法学习某些错误信息,我无法继续阅读直到错误被修复。
TylerH 2014年

@TylerH在浏览器中的此页面上执行Ctrl + F组合键,找到字符串“立即”(包括双引号),如果您理解错了,我认为
它就

64

Javascript的 this

简单函数调用

考虑以下功能:

function foo() {
    console.log("bar");
    console.log(this);
}
foo(); // calling the function

请注意,我们在正常模式下运行此程序,即未使用严格模式。

在浏览器中运行时,的值this将记录为window。这是因为它window是Web浏览器范围内的全局变量。

如果您在诸如node.js之类的环境中运行同一段代码,this则将引用您应用程序中的全局变量。

现在,如果我们通过"use strict";在函数声明的开头添加语句以严格模式运行此命令,则this在任何一个环境中都将不再引用全局变量。这样做是为了避免在严格模式下造成混淆。this在这种情况下,只需log undefined,因为它就是它,所以未定义。

在以下情况下,我们将看到如何操纵的值this

在对象上调用函数

有不同的方法可以做到这一点。如果您已经在Javascript中像forEach和一样调用了本机方法slice,则应该已经知道该this情况下的变量是指Object您在其上调用了该函数的变量(请注意,在javascript中,几乎所有内容都是一个Object,包括Arrays和Functions)。以下面的代码为例。

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.logThis;
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关键字调用该函数将立即初始化Objecttype Person
  2. 此构造函数的Object构造函数设置为Person。另外,请注意,这typeof awal只会返回Object
  3. 此新产品Object将分配给的原型Person.prototype。这意味着Person原型中的任何方法或属性都可用于的所有实例Person,包括awal
  4. Person现在,该函数本身被调用;this是对新建对象的引用awal

很简单,是吗?

请注意,官方ECMAScript规范无处声明此类功能是实际constructor功能。它们只是正常功能,new可以在任何功能上使用。只是我们原样使用它们,因此我们仅如此称呼它们。

在函数上调用函数:callapply

是的,因为functions也是Objects(实际上是Javascript中的第一类变量),所以即使函数也具有本身就是函数的方法。

所有函数都从global继承Function,其许多方法中的两个是callapply,并且这两个方法均可用于操纵this调用它们的函数中的value 。

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任何函数中的值的非常不错的方法。

applycallaccept 几乎相同,它只接受两个参数:thisArg一个数组,其中包含要传递给函数的参数。因此,上述call调用可以转换为apply以下形式:

foo.apply(thisArg, [1,2,3])

请注意,call并且apply可以覆盖this第二点中讨论的点方法调用设置的值。很简单:)

呈现.... bind

bind是的哥callapply。它也是所有函数从FunctionJava脚本的全局构造函数继承的方法。bindcall/ / 之间的区别applycallapply实际上都将调用该函数。bind另一方面,返回带有thisArgarguments预设的新函数。让我们举个例子来更好地理解这一点:

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和一样applybind也将超越的价值this点方法调用设置。

另请注意,这三个功能均未对原始功能进行任何更改。callapply从新构造的函数中返回值,而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嵌套范围更改了value ,但是我们希望this从原始范围更改。因此,我们“复制” thisthat了副本并使用了副本this。聪明吧?

指数:

  1. this默认情况下保留什么?
  2. 如果我们将该函数作为带有对象点表示法的方法来调用该怎么办?
  3. 如果我们使用 new关键字怎么办?
  4. 我们如何this使用call和操作apply
  5. 使用bind
  6. 复制this以解决嵌套范围问题。

47

“这”是关于范围的。每个函数都有自己的作用域,并且由于JS中的所有对象都是对象,所以即使一个函数也可以使用“此”将一些值存储到自身中。OOP 101教导“此”仅适用于对象的实例。因此,每次执行一个函数时,该函数的新“实例”就具有“ this”的新含义。

大多数人在匿名闭包函数中尝试使用“ this”时会感到困惑:

(函数(值){
    this.value =值;
    $('。some-elements')。each(function(elt){
        elt.innerHTML = this.value; //哦哦!可能未定义
    });
})(2);

所以在这里,在each()中,“ this”不包含您期望它(从

this.value =值;
它上面)。因此,要解决此问题(无双关语),开发人员可以:

(函数(值){
    var self = this; // 小变化
    self.value =值;
    $('。some-elements')。each(function(elt){
        elt.innerHTML = self.value; //!== 2
    });
})(2);

试试看; 您将开始喜欢这种编程模式


6
“ JS中的所有内容都是对象”不是正确的,JavaScript也具有原始值,请参见bclary.com/2004/11/07/#a-4.3.2
Marcel Korpel 2010年

6
基本值本身似乎具有一些方法,例如String#substring(),Number#toString()等。因此,也许它们的命名方式与该文章的名称不同,它们实际上的行为就像是对象(它们是所有原型,例如String#substring()实际上是:String.prototype.substring = function(){...})。如果我错了,请纠正我。
arunjitsingh

12
this关键字无关的范围。同样,它在不是对象属性的函数中也具有意义。
贝吉

1
@arunjitsingh-关于这方面有两种思想流派。我喜欢这样一个说法:“ 一切都是对象,但是为了方便起见,有些可以用原语表示 ”。;-)
RobG 2015年

9
this范围不是全部。这完全取决于执行上下文,这与作用域不同。JavaScript具有词法范围(意思是范围由代码的位置确定),但this取决于包含它的函数的调用方式-而不是该函数的位置。
Scott Marcus

16

由于该主题的进展,我为刚接触该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 strictthis在全球和在未绑定到任何物体匿名函数持有的价值undefined

在以下情况下,this关键字最容易被误解:1)我们借用了一个使用方法的方法this,2)我们this为变量分配了使用方法的方法,3)this用作回调函数的函数,以及4)this在闭包内部使用的方法—内部功能。(2)

表

什么把握未来

ECMA脚本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. this&Object Prototypes,作者:凯尔·辛普森(Kyle Simpson)。©2014 Getify解决方案。
  2. javascriptissexy.com- http://goo.gl/pvl0GX
  3. 安格斯卡罗尔-http: //goo.gl/Z2RacU

16

this在JavaScript中,总是指正在执行的函数的“所有者”

如果未定义任何显式所有者,则引用最高的所有者,即窗口对象。

所以如果我做到了

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

element.onclick = someKindOfFunction;

this将引用元素对象。但是要小心,很多人都会犯这个错误。

<element onclick="someKindOfFunction()">

在后一种情况下,您仅引用函数,而不将其移交给元素。因此,this将引用窗口对象。


15

JavaScript中的每个执行上下文都有一个this参数,参数由以下参数设置:

  1. 函数的调用方式(包括作为对象方法,使用callapply,使用new
  2. 绑定的使用
  3. 用词法表示箭头函数(它们采用外部执行上下文的this
  4. 代码是处于严格模式还是非严格模式
  5. 是否使用调用了代码 eval

您可以设置的值使用func.callfunc.applyfunc.bind

默认情况下,令大多数初学者感到困惑的是,在DOM元素上引发事件后调用侦听器时,,该函数值为DOM元素。

jQuery使用jQuery.proxy可以轻松地进行更改。


9
说每个函数调用都有作用域,这是正确的一点。换句话说,thisJavaScript 令人困惑的是它不是函数本身的固有属性,而是函数调用方式的产物。
Pointy 2010年

@pointy谢谢。在js中引起最大混乱的原因是,在较早使用的所有语言(c#,c ++)中,-不能操纵n总是指向对象实例,而在js中,它依赖于并且可以在调用时更改功能使用func.callfunc.bind等等-苏希尔
苏希尔

2
this没有引用函数的作用域。this将引用一个特定的对象(或可能undefined),正如您所说的,可以使用.call()或对其进行更改.apply()。函数的作用域(基本上是简化时)是它可以访问的变量,而这完全取决于函数在何处声明且不能更改。
nnnnnn

@Pointy:“说每个函数调用都有作用域是正确的。” 更准确地说,函数(以及现在的块)具有作用域,函数调用具有context。范围定义了该范围内的代码可以使用的标识符。上下文定义了这些标识符绑定的对象。
TJ Crowder

1
“无论范围是什么,都用“ this”来引用。” 不,this范围与ES5及之前的版本(例如,写此答案的时间)之间没有任何关系。在ES2015(又名ES6)中,this作用域与wrt箭头功能(箭头功能是从其封闭的作用域继承而来)以一种相当最小的方式相关this,但this从未引用作用域。
TJ Crowder

10

thisin的一个好来源JavaScript

这是摘要:

  • 全球这个

    在浏览器中,在全局范围内thiswindow对象

    <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提供a的情况下(请参阅下一节),在节点和浏览器中都使用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;,在这种情况下thisundefined

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

如果你调用一个函数newthis将是一个新的环境,也不会引用全局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本

您可以在其中放置JavaScript的HTML属性内部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>

9

丹尼尔,很棒的解释!this在事件处理程序的情况下,这两个单词是很好的执行上下文指针列表。

用两个词this在JavaScript中指出运行当前函数的对象(或从其执行上下文),并且该对象始终是只读的,您无论如何都无法设置它(这样的尝试将以“无效的左手结尾分配中的信息”。

对于事件处理程序:内联事件处理程序(例如<element onclick="foo">)会覆盖之前和之前附加的所有其他处理程序,因此请当心,最好不要使用内联事件委托。还要感谢Zara Alaverdyan,他通过一次持异议的辩论启发了我列举了以下示例:)

  • 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)">

9

关于如何在JavaScript中解释“ this”关键字存在很多困惑。希望本文能使所有这些东西一劳永逸。还有更多。请仔细阅读整篇文章。请注意,本文篇幅较长。

无论使用哪种上下文,“ this”始终引用Javascript中的“当前对象”。但是,“当前对象”的含义根据上下文而有所不同。所述上下文可以是恰好1 6的以下情况:

  1. 全局(即在所有功能之外)
  2. 内部直接“非绑定函数”调用(即,尚未通过调用functionName.bind绑定的函数
  3. 内部间接“非绑定函数”通过functionName.callfunctionName.apply调用
  4. 内部“绑定函数”调用即已通过调用functionName.bind绑定函数
  5. 而通过“新建”创建对象
  6. 内部内联DOM事件处理程序

下面逐一描述每种情况:

  1. 全局上下文(即在所有功能之外):

    在所有函数之外(即,在全局上下文中),“当前对象”(因此是“ this”的值)始终是浏览器的 “窗口”对象。

  2. 内部直接“无界函数”调用

    在直接的“非绑定函数”调用中,调用该函数调用的对象将成为“当前对象”(并因此成为“ this”的值)。如果在没有显式当前对象的情况下调用函数,则当前对象“窗口”对象(对于非严格模式)或未定义(对于严格模式)。全局上下文中定义的任何函数(或变量)都会 自动成为“窗口”对象的属性。例如,假设函数在全局上下文中定义为

    function UserDefinedFunction(){
        alert(this)
        }

    它成为窗口对象的属性,就像您已将其定义为

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

    在“非严格模式”下,直接通过“ UserDefinedFunction()”调用/调用此函数 会自动将其作为“ window.UserDefinedFunction()”进行调用/调用,从而使“ window”成为 “当前对象”(因此,“ “”“ UserDefinedFunction ”中)。在“非严格模式”下调用此函数将导致以下情况

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

    在“严格模式”下,直接通过“ UserDefinedFunction()”调用/调用该函数 将“不”自动将其作为“ window.UserDefinedFunction()”调用/调用。因此,“当前对象”(以及“ this”的值)) “ UserDefinedFunction”中的)应为undefined。在“严格模式”下调用此功能将导致以下情况

    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

    在上面的示例中,我们看到当通过o1调用“ UserDefinedFunction”时,“ this”的值为o1,并且显示其属性“ a”“ b”的值。的值“C”“d”被示出为未定义O1没有定义这些属性

    类似地,当通过o2调用“ UserDefinedFunction”时, “ this”取值为o2并显示其属性“ c”“ d”的值。与o2一样,“ a”“ b”的值显示为未定义没有定义这些属性。

  3. 内部间接“非绑定函数”通过functionName.callfunctionName.apply调用

    当一个“非绑定函数”是通过称为 functionName.callfunctionName.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

    上面的代码清楚地表明,可以通过call / apply更改任何“ NON Bound Function”的“ this”值。另外,如果未将 “ this”参数显式传递给call / apply,则在非严格”模式下,“当前对象”(因此,“ this”的值)将设置为“窗口”,在严格模式下将设置为“未定义”

  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”值都不能通过call / apply进行更改。另外,如果 未明确传递“ this”参数进行绑定,则在非严格”模式下将“当前对象” (因此将“ this”的值)设置为“ window”,在严格模式下将设置为“ undefined”。还有一件事。绑定已经绑定的函数不会更改“ this”的值。它仍然设置为第一个绑定函数设置的值。

  5. 通过“ new”创建对象时

    在构造函数中,“当前对象”(因此是“ this”的值 )引用当前通过“ new”创建的对象,而与函数的绑定状态无关。但是,如果构造函数是绑定函数,则应使用为绑定函数设置的预定义参数集来调用它。

  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”元素时,它将使用其第二个参数引用被单击的div元素来调用OnDivClick函数。但是, OnDivClick中的“ this”不应引用所单击的div 元素。应分别在严格模式严格模式下将其设置为“窗口对象”“未定义”(如果OnDivClick未绑定函数),或者设置为预定义的Bound值(如果OnDivClick绑定函数

以下总结了整篇文章

  1. 在全局上下文中,“ this”始终引用“ window”对象

  2. 每当调用函数时,都会在对象(“当前对象”)的上下文中调用该函数。如果当前对象没有明确规定,在当前的对象“窗口对象”非严格模式“未定义”在默认情况下,严格模式。

  3. Non Bound函数中的“ this”的值是对调用该函数的对象的引用(“当前对象”

  4. Non Bound函数中的“ this”值可以通过调用应用函数的方法来覆盖 。

  5. 对于绑定函数,“ this”的值是固定的,不能被该函数的调用应用方法覆盖。

  6. 绑定和已经绑定的函数不会更改“ this”的值。它仍然设置为第一个绑定函数设置的值。

  7. 构造函数中“ this”的值是正在创建和初始化的对象

  8. 内联DOM事件处理程序中的“ this”的值引用为其提供事件处理程序的元素。


9

关于this以下内容的最详细,最全面的文章可能是:

在JavaScript中对“ this”关键字的温和解释

背后的想法this是要了解函数调用类型对于设置this值具有重要意义。


在确定问题时this不要问自己:

从哪里this带走的

不要问自己:

该函数如何调用

对于箭头功能(上下文透明的特殊情况),请问自己:

this定义箭头功能的地方有什么值?

这种心态在与人打交道时是正确的this,它将使您免于头痛。


除了链接到您的博客之外,也许您可​​以更深入地研究提出这些问题如何帮助某人理解this关键字?
Magnus Lind Oxlund,

7

这是我见过的最好的解释:了解JavaScript的这种清晰

引用总是指(并保持的值)的物体的单一对象,而且它通常是一个函数或方法内使用,虽然它可以在函数外,在全球范围内使用。请注意,当我们使用严格模式时,它在全局函数和未绑定到任何对象的匿名函数中都具有未定义的值。

有四个场景中可能会造成混淆:

  1. 当我们传递一个方法(使用this)作为参数用作回调函数时。
  2. 当我们使用内部函数(闭包)时。请务必注意,闭包无法使用this关键字访问外部函数的this变量,因为this变量只能由函数本身访问,而不能由内部函数访问。
  3. 当其依赖于一个方法被分配给跨过上下文的变量,在这种情况下,引用另一个目的比最初预期。
  4. 当使用这种与绑定一起,应用和调用方法。

他提供了代码示例,解释和解决方案,我认为这非常有帮助。


6

用伪古典术语来说,许多课程讲授“ 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;

5

this是JavaScript中一个被误解的概念之一,因为它的行为因地而异。简单来说,this是指我们当前正在执行的函数“所有者”

this帮助获取我们正在使用的当前对象(又名执行上下文)。如果你了解这是越来越当前执行的函数对象,你可以很容易地了解当前thisIS

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内部,另一个在obj的innerMethod内部。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()执行new时,将创建一个全新的对象。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元素。



5

“ this”的值取决于在其中执行功能的“上下文”。上下文可以是任何对象或全局对象,即窗口。

因此,“ this”的语义不同于传统的OOP语言。这会导致问题:1.将函数传递给另一个变量时(很可能是回调);2.从类的成员方法调用闭包时。

在两种情况下,都将其设置为window。


3

对子级帮助?(JavaScript中的“ this”最令人困惑的原因是,它通常不链接到您的对象,而是链接到当前的执行范围-可能不完全是它的工作方式,但在我看来总是这样-请参阅文章以获取完整说明)


1
最好将其链接到“当前执行上下文 ”。除了ES6(草稿)使用箭头功能进行了更改外,这在外部执行上下文中得以解决。
RobG

3

有关此的一点信息关键字的

让我们this在全局范围内将关键字记录到控制台中,无需任何其他代码,但

console.log(this)

Client / Browser中, this关键字是一个全局对象,它是window

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

Server / Node / Javascript中,runtime this关键字也是一个全局对象,它是module.exports

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

记住exports只是对module.exports


1

像这样用于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')是相同的


1

我有不同的看法 this对其他答案,希望对您有所帮助。

查看JavaScript的一种方法是看到只有一种方法可以调用函数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.bJavaScript时,首先会查找a属性直接为所引用的对象b。如果b未在对象上找到JavaScript,则JavaScript将在对象的原型中查找find 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();  

经过翻译使用callobj.bar()成为const temp = obj.bar; temp.call(obj);。当我们进入bar函数时,我们会调用,foo但是我们为objectForThis显式传递了另一个对象,因此当我们到达foo时this就是该内部对象。

bind=>功能都是有效的。它们是语法更多的糖。他们有效地构建了一个新的不可见函数,就像bar上面的函数一样,它this在调用指定的函数之前先进行了显式设置。如果bind 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到新的不可见函数并返回分配给的新不可见函数bb()将像往常一样工作b.call(window)b.call(undefined)调用foo创建的新的不可见函数。该不可见函数将忽略this传递给它的内容,并将其obj作为objectForThis` 传递给arrow函数。

上面的代码转换为

function foo() {
  function tempFn() {
    console.log(this);
  }
  return tempFn.bind(this);
}

const obj = {
  foo,
};
const b = obj.foo();
b.call(window or undefined if strict mode);

1apply是类似于call

functionName.apply(objectForThis, arrayOfArgs);

但从ES6概念上讲,您甚至可以将其转换为

functionName.call(objectForThis, ...arrayOfArgs);

0

摘要thisJavascript:

  • 的值this取决于函数的调用方式(在何处创建)!
  • 通常,的值this由点左侧的对象确定。(window在全球范围内)
  • 在事件侦听器中,的值this 引用在其上调用事件的DOM元素。
  • 当使用new关键字调用in函数时,的值this引用新创建的对象
  • 你可以操纵的价值this与功能:callapplybind

例:

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.


0

要正确理解“此”,必须了解上下文,范围以及它们之间的区别。

范围:在javascript中,范围与变量的可见性有关,范围通过使用函数来实现。(了解有关范围的更多信息)

上下文:上下文与对象有关。它是指功能所属的对象。当您使用JavaScript“ this”关键字时,它指向函数所属的对象。例如,在函数内部,当您说:“ this.accoutNumber”时,您所指的是属性“ accoutNumber”,该属性属于该函数所属的对象。

如果对象“ myObj”具有名为“ getMyName”的方法,则当在“ getMyName”内部使用JavaScript关键字“ this”时,它称为“ myObj”。如果函数“ getMyName”是在全局范围内执行的,则“ this”是指窗口对象(严格模式下除外)。

现在让我们看一些例子:

    <script>
        console.log('What is this: '+this);
        console.log(this);
    </script>

浏览器输出中的Runnig上面的代码将: 在此处输入图片说明

根据输出,您在窗口对象的上下文内部,也可以看到窗口原型引用该对象。

现在让我们尝试一个函数内部:

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

输出: 在此处输入图片说明

现在让我们了解一下范围,自我,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

简单答案:

“ this”关键字始终取决于调用的上下文。它们在下面提到。

  1. 使用新关键字调用功能

    如果使用NEW关键字调用该函数,则THIS将绑定到新创建的对象。

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

    在上面,这将绑定到“ myCar”对象

  2. 使用呼叫和应用方法明确调用功能。

    在这种情况下,THIS将绑定到显式传递给函数的对象。

    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. 
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.