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

3

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


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

在上面的代码中,这两行最终都会记录浏览器中的Window对象。难道它不应该记录null吗?因为我在两种方法的第一个参数中传递了null。
2个回答

2
MDN

提供给fun调用的this值。请注意,方法实际上看到的可能不是这个值:如果该方法是非严格模式代码中的函数,则null和undefined将被替换为全局对象,并且原始值将被封装。

全局对象是window。

编辑,因为传入null、undefined或带有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 将指向传递进来的对象。

查看此 JSFiddle


1
好的,var stringToEval = "console.log(this)"; eval.call({}, stringToEval); eval.call("", stringToEval); eval.call({not : "empty"}, stringToEval); 仍然返回 Window 对象... 它不再是 null 或 undefined... - João Pinto Jerónimo
这是一个间接的 eval 调用,this 总是 window。它与 .call.apply 没有任何关系。 - Esailija
@JoãoPintoJerónimo 没问题 :) 这绝对是一个有趣的问题 :) - Paul

0

当你使用eval并将this显式设置为null时,这与在evaled代码内部的this对象无关。没有任何地方说eval会使用与调用eval相同的this进行评估。事实上,这样做是间接调用eval,对于现代浏览器,结果是在全局上下文中运行eval代码。

因此,您需要使用普通函数进行测试:

function test() {
    console.log(this);
}

test.call({});
test.apply({});

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接