为什么这个闭包有效?

8

假设我有一个简单的函数,它可以弹出一条消息:

function callMessage(msg){
        alert(msg);
    }

现在当我这样调用它时,它不起作用。会抛出错误"hey未定义"。
function sayHi(){
        var hey = "hi there"
        setTimeout("callMessage(hey)", 1000);
    }
    sayHi();

但是当我在匿名函数内调用它时,它可以正常工作:

function sayHi(){
        var hey = "hi there"
        setTimeout(function(){callMessage(hey);}, 1000);
    }
    sayHi();

为什么只有当我将“hey”变量放在匿名函数内部时才能看到它?

1
我也会尝试这个:setTimeout("var hey = 'hi there'; callMessage(hey)", 1000); - mindandmedia
如果我是你,我会阅读类似于http://www.digital-web.com/articles/scope_in_javascript/的内容。 - Paul Grime
3个回答

14
在第一个示例中,代码在计时器过期和当前范围离开后被评估。此时hey未定义。
第二个示例 - 使用setTimeout的正确方法 - 在调用setTimeout()时创建一个匿名函数。这个匿名函数也会接收当前范围的副本。

在第二个示例中,闭包的主体也不会被评估,直到那时为止。 - sepp2k
2
直到稍后才会被执行。第一个是通过eval()字面上评估的,没有提示要使用哪个范围,因为它只是一个字符串。 - Linus Kleen
那很有道理。我不知道匿名函数有其父级作用域的副本。 - levi

6
"

"callMessage(hey)"是一个字符串,而不是闭包。当超时运行时,它会被评估,在这一点上,变量hey不在作用域内。

"

3

这是正常的。

第二个例子创建了我们所谓的fixture,这是一个执行上下文。变量hey被保存在内存中以便于匿名函数使用。

在你的第一个例子中,hey变量没有被保存在fixture中(因为javascript不知道你会在之后使用该变量),所以在字符串被评估时无法检索到它。


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