javascript - “this”关键字如何工作?

标签 javascript this

我注意到,似乎没有明确解释this关键字是什么,以及如何在Stack Overflow网站上的JavaScript中正确(和不正确地)使用它。

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

this如何工作,何时应使用?

最佳答案

我建议先阅读Mike West的文章Scope in JavaScriptmirror)。这是对JavaScript中this和作用域链的概念的出色而友好的介绍。

一旦开始习惯this,规则实际上非常简单。 ECMAScript 5.1 Standard定义this


  §11.1.1 this关键字
  
  this关键字的值等于当前执行上下文的ThisBinding的值


这个绑定是JavaScript解释器在评估JavaScript代码时所维护的,例如特殊的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.4.1.1)。

输入评估码


…直接致电eval()
ThisBinding保持不变;它与调用执行上下文的ThisBinding(§10.4.2(2)(a))的值相同。
…如果不是直接致电eval()
将这个Binding设置为全局对象,就好像在初始全局执行上下文(§10.4.2(1))中执行一样。


§15.1.2.1.1定义了直接调用eval()的含义。基本上,eval(...)是直接调用,而类似(0, eval)(...)var indirectEval = eval; indirectEval(...);的东西是对eval()的间接调用。有关何时可以使用间接eval()调用的信息,请参见chuckj's answer(1, eval)('this') vs eval('this') in JavaScript?Dmitry Soshnikov’s ECMA-262-5 in detail. Chapter 2. Strict Mode.

输入功能码

调用函数时会发生这种情况。如果在对象上(例如,在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;否则,转到全局对象。

这些是纯JavaScript的规则。当您开始使用JavaScript库(例如jQuery)时,您可能会发现某些库函数会操纵this的值。这些JavaScript库的开发人员这样做是因为它倾向于支持最常见的用例,并且该库的用户通常会发现此行为更加方便。将引用this的回调函数传递给库函数时,应确保在调用该函数时有关this的值的任何保证,请参考文档。

如果您想知道JavaScript库如何处理this的值,则该库仅使用接受thisArg的内置JavaScript函数之一。您也可以使用回调函数和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);


箭头功能

Arrow functions(在ECMA6中引入)更改了this的范围。有关更多信息,请参见现有的规范问题Arrow function vs function declaration / expressions: Are they equivalent / exchangeable?。简而言之:


  箭头函数没有自己的this ....绑定。
  相反,这些标识符像任何其他方法一样在词法范围内解析
  其他变量。这意味着在箭头函数中,this ...指的是环境中this的值
  定义了箭头功能。


只是为了好玩,用一些例子测试您的理解

要显示答案,请将鼠标悬停在浅黄色框上。


标记的行中this的值是什么?为什么?


   window —在初始全局执行上下文中评估标记的行。


if (true) {
    // What is `this` here?
}

当执行this时,标记行上的obj.staticFunction()值是什么?为什么?


   obj —在对象上调用函数时,ThisBinding设置为该对象。




var obj = {
    someData: "a string"
};

function myFun() {
    return this // What is `this` here?
}

obj.staticFunction = myFun;

console.log("this is window:", obj.staticFunction() == window);
console.log("this is obj:", obj.staticFunction() == obj);
  




标记的行中this的值是什么?为什么?


   window

 在此示例中,JavaScript解释器输入函数代码,但是由于未在对象上调用myFun / obj.myMethod,因此ThisBinding设置为window

 这与Python不同,在Python中,访问方法(obj.myMethod)创建一个bound method object




var obj = {
    myMethod: function () {
        return this; // What is `this` here?
    }
};
var myFun = obj.myMethod;
console.log("this is window:", myFun() == window);
console.log("this is obj:", myFun() == obj);
  




标记的行中this的值是什么?为什么?


   window

 这个很棘手。评估评估代码时,thisobj。但是,在评估代码中,未在对象上调用myFun,因此对于该调用,ThisBinding设置为window


 

function myFun() {
    return this; // What is `this` here?
}
var obj = {
    myMethod: function () {
        eval("myFun()");
    }
};

标记的行中this的值是什么?为什么?


   obj

 myFun.call(obj);行正在调用特殊的内置函数Function.prototype.call(),该函数接受thisArg作为第一个参数。




function myFun() {
    return this; // What is `this` here?
}
var obj = {
    someData: "a string"
};
console.log("this is window:", myFun.call(obj) == window);
console.log("this is obj:", myFun.call(obj) == obj);
  

关于javascript - “this”关键字如何工作?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47643862/

相关文章:

javascript - 如何将 $(this) 传递给函数?

javascript - 如何在 ASP.NET 表单上使用 javascript 调用回发

javascript - 使用 $(this) 和 jQuery 访问内部文本

带有 $(this) 的 jQuery 多重选择器

javascript - mocha测试中以下js箭头函数中 `this`指向什么?

java - 在自维护的单例类中使用this关键字或者总是使用instance

javascript - Electron 中的定时功能

javascript - 如何在 Typescript 中进行后期绑定(bind)

javascript - 将特定值注入(inject)对象构造函数

javascript - net::ERR_FAILED 用于 manifest.cache 中的网络项