我在阅读Angus Croll理解JS的博客时发现了这个
var a = {
b: function() {
var c = function() {
return this;
};
return c();
}
};
a.b();//window
在我看来,在调用c的时候,c在b内部。这应该是调用上下文(如果我错了,请纠正我)。当它执行时,为什么c()的上下文(this)是window?
我在博客中发现了另一个例子
var a = {
b: function() {
return (function() {return this;})();
}
};
a.b(); //window
为什么b的上下文是window?匿名函数总是在全局上下文中运行吗?
以下是理解this
(双关语)的好方法:
函数内部this
的值由函数的调用方式决定。除了一个例外,它与函数在哪里定义、它可能嵌套在什么其他函数中、它被定义为什么对象的一部分、它是什么类型的函数或任何这些都无关。
当使用类似foo.bar()
或foo[bar]()
的方法调用函数时,函数内的this
是foo
对象。
当使用普通函数调用(如foo()
)调用函数时,函数中的this
是window
对象,或者如果函数使用严格模式,则为undefined
。
这是一个例外——如果函数本身或其周围的代码具有"use strict";
,那么它会为普通函数调用更改this
。对于不应该有区别的好代码,您不应该编写依赖于this
作为window
对象的代码。
否则,您关心的是this
在方法调用中引用了什么对象。这总是由函数的调用方式决定的,而不是它的定义方式。
让我们来看看你的第一个例子。
当您调用a.b()
时,您将调用b
作为a
对象的方法。因此,在b
函数中,this
与a
相同。
碰巧的是,知道这一点对我们没有任何好处,因为b
函数从未对this
做过任何事情。它所做的只是将c()
作为一个普通函数调用。因此,在c
中,this
是window
对象,或者如果您处于严格模式,它将是undefined
。
c
函数只是返回其this
值或window
。这也是b
的返回值。这就是为什么您看到window
作为结果:这一切都来自于代码如何调用b
和c
函数。
现在来看第二个例子:好吧,这只是非常模糊的代码,不是吗?谁会写下这段代码,并期望任何人第一眼就能理解它?
所以让我们把它变成一个可读性更强的形式
return (function() {return this;})();
让我们去掉带括号的函数表达式:
(function() {return this;})
并将其分配给一个临时变量:
var temp = (function() {return this;});
我们不再需要额外的括号,为了可读性,让我们缩进代码:
var temp = function() {
return this;
};
我们可以将temp
变量作为return
语句中的函数调用:
return temp();
现在我们可以将其放回代码示例中的b
函数中:
var a = {
b: function() {
var temp = function() {
return this;
};
return temp();
}
};
a.b(); //window
嘿!那个代码看起来不熟悉吗?事实上,除了temp
变量的名称之外,它与第一个示例完全相同。现在你明白为什么它和第一个一样工作了。
需要查找的一个关键字是new
关键字,它建立了一个新的上下文。没有看到new
?那么上下文没有改变,这意味着this
没有改变。如果你在window
中调用它,那么这就是你的上下文,那就是你的this
。(如果将call()
或apply()
与作用域一起使用,则情况会发生变化,但这显然不适用于此处。)