“这个”怎么样?关键词工作? [英] How does the "this" keyword work?

查看:115
本文介绍了“这个”怎么样?关键词工作?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我注意到似乎没有明确解释这个关键字是什么以及它在JavaScript中如何正确(和错误地)使用Stack Overflow site。

I have noticed that there doesn't appear to be a clear explanation of what the this keyword is and how it is correctly (and incorrectly) used in JavaScript on the Stack Overflow site.

我目睹了一些非常奇怪的行为并且无法理解为什么会发生这种情况。

I have witnessed some very strange behaviour with it and have failed to understand why it has occurred.

如何工作以及何时使用?

推荐答案

我建议阅读 Mike West 的文章 JavaScript范围镜像)首先。这是对JavaScript中这个和范围链的概念的一个很好的友好介绍。

I recommend reading Mike West's article Scope in JavaScript (mirror) first. It is an excellent, friendly introduction to the concepts of this and scope chains in JavaScript.

一旦你开始得到曾经这个,规则实际上非常简单。 ECMAScript 5.1标准定义

Once you start getting used to this, the rules are actually pretty simple. The ECMAScript 5.1 Standard defines this:


§11.1.1 关键字



关键字求值为当前执行上下文的ThisBinding的值

§11.1.1 The this keyword

The this keyword evaluates to the value of the ThisBinding of the current execution context

ThisBinding是JavaScript解释器在评估JavaScript代码时维护,就像一个特殊的CPU寄存器,它保存对象的引用。只要在三种不同情况中的一种情况下建立执行上下文,解释器就会更新ThisBinding:

ThisBinding is something that the JavaScript interpreter maintains as it evaluates JavaScript code, like a special CPU register which holds a reference to an object. The interpreter updates the ThisBinding whenever establishing an execution context in one of only three different cases:

这是在顶层评估的JavaScript代码的情况,例如:当直接在< script> 中:

This is the case for JavaScript code that is evaluated at the top-level, e.g. when directly inside a <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 )。

When evaluating code in the initial global execution context, ThisBinding is set to the global object, window (§10.4.1.1).


  • ...通过直接调用 eval()
    ThisBinding保持不变;它与调用执行上下文的ThisBinding值相同(§10.4 .2 (2)(a))。

...如果没有通过直接调用 eval()

ThisBinding设置为全局对象,就好像在初始全局执行上下文中执行一样(§10.4.2(1))。

…if not by a direct call to eval()
ThisBinding is set to the global object as if executing in the initial global execution context (§10.4.2 (1)).

§15.1.2.1.1定义了对 eval()的直接调用是什么。基本上, eval(...)是直接调用,而类似(0,eval)(...) var indirectEval = eval; indirectEval(...); 是对 eval()的间接调用。请参阅 chuckj的答案(1 ,eval)('this')与JavaScript中的eval('this')? Dmitry Soshnikov的ECMA-262-5详细说明。第2章严格模式。用于何时使用间接 eval()调用。

§15.1.2.1.1 defines what a direct call to eval() is. Basically, eval(...) is a direct call whereas something like (0, eval)(...) or var indirectEval = eval; indirectEval(...); is an indirect call to eval(). See chuckj's answer to (1, eval)('this') vs eval('this') in JavaScript? and Dmitry Soshnikov’s ECMA-262-5 in detail. Chapter 2. Strict Mode. for when you might use an indirect eval() call.

调用函数时会发生这种情况。如果在对象上调用函数,例如 obj.myMethod()或等价的 obj [myMethod](),然后将ThisBinding设置为对象(示例中为 obj ; §13.2.1)。在大多数其他情况下,ThisBinding设置为全局对象(§10.4。 3 )。

This occurs when calling a function. If a function is called on an object, such as in obj.myMethod() or the equivalent obj["myMethod"](), then ThisBinding is set to the object (obj in the example; §13.2.1). In most other cases, ThisBinding is set to the global object (§10.4.3).

在大多数其他情况下编写的原因是因为有8个ECMAScript 5内置函数允许在此指定ThisBinding参数列表。这些特殊函数采用所谓的 thisArg ,在调用函数时成为ThisBinding(§10.4.3

The reason for writing "in most other cases" is because there are eight ECMAScript 5 built-in functions that allow ThisBinding to be specified in the arguments list. These special functions take a so-called thisArg which becomes the ThisBinding when calling the function (§10.4.3).

这些特殊的内置函数是:

These special built-in functions are:


  • Function.prototype.apply(thisArg,argArray)

  • Function.prototype.call(thisArg [,arg1 [,arg2,...]])

  • Function.prototype.bind(thisArg [,arg1 [,arg2,...]])

  • 数组。 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.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

In the case of the Function.prototype functions, they are called on a function object, but rather than setting ThisBinding to the function object, ThisBinding is set to the thisArg.

对于 Array.prototype 函数,调用给定的 callbackfn 在执行上下文中,ThisBinding设置为 thisArg (如果提供);否则,到全局对象。

In the case of the Array.prototype functions, the given callbackfn is called in an execution context where ThisBinding is set to thisArg if supplied; otherwise, to the global object.

这些是纯JavaScript的规则。当您开始使用JavaScript库(例如jQuery)时,您可能会发现某些库函数操纵这个的值。这些JavaScript库的开发人员这样做是因为它倾向于支持最常见的用例,并且库的用户通常会发现这种行为更方便。当将这个的回调函数传递给库函数时,你应该参考文档以获得关于这个是调用该函数的时候。

Those are the rules for plain JavaScript. When you begin using JavaScript libraries (e.g. jQuery), you may find that certain library functions manipulate the value of this. The developers of those JavaScript libraries do this because it tends to support the most common use cases, and users of the library typically find this behavior to be more convenient. When passing callback functions referencing this to library functions, you should refer to the documentation for any guarantees about what the value of this is when the function is called.

如果您想知道JavaScript库如何操作这个的值,该库只是使用一个内置的JavaScript函数接受 thisArg 。您也可以使用回调函数编写自己的函数, thisArg

If you are wondering how a JavaScript library manipulates the value of this, the library is simply using one of the built-in JavaScript functions accepting a thisArg. You, too, can write your own function taking a callback function and thisArg:

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

我还没有提到一个特例。通过 new 运算符构造新对象时,JavaScript解释器会创建一个新的空对象,设置一些内部属性,然后在新对象上调用构造函数。因此,当在构造函数上下文中调用函数时, this 的值是解释器创建的新对象:

There’s a special case I didn’t yet mention. When constructing a new object via the new operator, the JavaScript interpreter creates a new, empty object, sets some internal properties, and then calls the constructor function on the new object. Thus, when a function is called in a constructor context, the value of this is the new object that the interpreter created:

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



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



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


  1. 什么是标记行的的值是多少?为什么?

  1. What is the value of this at the marked line? Why?


window - 标记的行在初始全局执行上下文。

window — The marked line is evaluated in the initial global execution context.



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


  • 这个<的价值是多少? / code>在执行 obj.staticFunction()时标记的行?为什么?

  • What is the value of this at the marked line when obj.staticFunction() is executed? Why?


    obj - 调用函数时对象,ThisBinding设置为对象。

    obj — When calling a function on an object, ThisBinding is set to the object.

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

    这个在标记的行?为什么?

    What is the value of this at the marked line? Why?


    window

    在此示例中,JavaScript解释器输入功能代码,但因为 myFun / obj.myMethod 不是调用一个对象,ThisBinding设置为 window

    这与Python不同,在Python中访问方法( obj.myMethod )会创建绑定方法对象

    window

    In this example, the JavaScript interpreter enters function code, but because myFun/obj.myMethod is not called on an object, ThisBinding is set to window.

    This is different from Python, in which accessing a method (obj.myMethod) creates a 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);
      

    这个在标记的行?为什么?

    What is the value of this at the marked line? Why?


    window

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

    window

    This one was tricky. When evaluating the eval code, this is obj. However, in the eval code, myFun is not called on an object, so ThisBinding is set to window for the call.





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


  • 这个在标记线?为什么?


    obj

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

    obj

    The line myFun.call(obj); is invoking the special built-in function Function.prototype.call(), which accepts thisArg as the first argument.

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

    这篇关于“这个”怎么样?关键词工作?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

  • 查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆