了解.call和.apply在Javascript中的行为

时间:2012-06-07 05:25:31

标签: javascript function this

我从MDN文档中读到.apply和.call的第一个参数是“this”对象,但是

var stringToEval = "console.log(this)";
eval.call(null, stringToEval);
eval.apply(null, [stringToEval]);

在上面的代码中,两行最终都记录了Window对象(在浏览器中)。它不应该记录null,这是我作为两个方法中的第一个参数传递的内容吗?

2 个答案:

答案 0 :(得分:2)

来自MDN

  

为乐趣召唤提供的价值。请注意,这可能不是方法看到的实际值:如果方法是非严格模式代码中的函数,则null和undefined将替换为全局对象,并且原始值将被装箱。

全局对象是窗口。

编辑,因为无论是传入null,未定义还是带有eval的对象都无关紧要。在eval内,this将在eval调用之前与this相同。

根据ECMA-262 5.1的第15.1.2.1节,eval接受一个字符串并将其解析为ECMAscript。如果它是有效的ECMAscript,那么它将在调用它的上下文中运行它。因此,在您的情况下,您可以将对eval的调用视为在运行时将它们替换为console.log(this)。通过该替换,您最终得到了该程序:

var stringToEval = "console.log(this)";
console.log(this);
console.log(this);

这清楚了为什么它输出DOMWindow对象两次。你可以像这样绕过它:

var stringToEval = "console.log(this)";
(function(str){ eval(str); }).call({not: "empty"}, stringToEval);
(function(str){ eval(str); }).apply({not: "empty"}, [stringToEval]);

因为当eval用console.log(this)替换它时,它将位于匿名函数的上下文中,其中this将引用传入的对象。

See this JSFiddle

答案 1 :(得分:0)

您通过明确将eval设置为this来致电null,这与this对象内部的内容无关 代码,没有任何地方说eval评估代码,this设置为与this调用的eval相同的eval。实际上,这样做是调用function test() { console.log(this); } test.call({}); test.apply({}); indirectly并导致eval代码在现代浏览器的全局上下文中运行。

因此,您希望使用正常功能进行测试:

{{1}}