“这个”怎么样?关键词工作? [英] How does the "this" keyword work?
问题描述
我注意到似乎没有明确解释这个
关键字是什么以及它在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
keywordThe
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);
只是为了好玩,用一些例子测试你的理解
要显示答案,请将鼠标悬停在淡黄色框上。
-
什么是标记行的
此
的值是多少?为什么?
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 towindow
.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
isobj
. However, in the eval code,myFun
is not called on an object, so ThisBinding is set towindow
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 functionFunction.prototype.call()
, which acceptsthisArg
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屋!