为什么在自执行函数中执行对象上的函数?

13
我有一个应用程序,在调试模式下,它由许多单独的JavaScript文件编写,但作为页面头部的一部分同步加载。在发布时,我将所有这些文件合并并进行缩小处理。今天我发现缩小版本中出现了一个错误,因此我加载了一个单个合并的文件来调试问题,并发现一个库正在自我执行函数,这导致其他在window上定义的函数被执行。
我已经使用通用对象重现了此行为,无论是window还是其他对象都没有关系:
<head>
    <script>
        var a = {}

        a.X = function x(){
            console.log("shouldn't be executed");
        }

        (function(a){
            console.log("self execution");
        }(a));
     </script>
</head>

在这个例子中,我获取了输出。
self execution 
shouldn't be executed 

如果我将调用更改为

<head>
    <script>
        var a = {}

        function x(){
            console.log("shouldn't be executed");
        }

        a.X = x;

        (function(a){
            console.log("self execution");
        }(a));
     </script>
</head>

然后我只需要得到

self execution

这正是我预料中的。在第一个例子中,当a被传递给自执行函数时,为什么会调用X


我很困惑为什么这样一个问题会在短时间内得到那么多的赞...是因为它被标记为Javascript,并且具有不明显的行为吗...? - Lekensteyn
10
活生生的例证,表明你应该使用分号 =D - Esailija
4
@Lekensteyn 这是一个有趣的谜题,与在for循环中设置事件处理程序无关。 - Pointy
@Esailija 还有,以一元加号和减号开头的行 - John Dvorak
2
这个 bug 是一个特性。 - Daniel W.
显示剩余5条评论
3个回答

22

在你将函数分配给 a.X 之后,你缺少了 ;

分号插入不会被触发。

匿名函数周围的 () 用于调用前一个函数,并将其返回值分配给 X

也就是说,你所拥有的等同于:

var a = {};

a.X = (function x(){
    console.log("shouldn't be executed");
}(
    (function(a){
        console.log("self execution");
    }(a))
));

顺便说一下,这个问题是一个宣传JS Lint的好机会,因为它可以发现这个问题。


2
哈哈,我刚刚注意到了。这就是为什么你应该使用分号! - Naftali
@asawyer — 我想得太远了,已经修复。 - Quentin
哈,太棒了。谢谢。也因此它运作起来时加载多个文件是很有道理的,这样它们就没有机会以这种方式相互执行。当我把所有东西合并到一个文件中后,突然分号变得重要了。 - devshorts
@CrazyTrain 我可以尝试一下,但我怀疑它不会很快变得流行。 - John Dvorak
1
@JanDvorak:Facebook已知使用它,像我这样在JS和Go中省略分号的人也使用它。这只是改变编码习惯的问题。好处是一旦你进入模式,你就不会被抓个措手不及,而如果你通常使用分号,但忘记了一些(就像OP一样),那么除非你使用更安全的运算符,否则你会遇到错误。 - user2437417
显示剩余9条评论

3

这与分号注入有关,因为当我加入分号时它按预期工作:

    var a = {}

    a.X = function x(){
        console.log("shouldn't be executed");
    }; // added semicolon

    (function(a){
        console.log("self execution");
    }(a));

1

你在 a.X = function x() { ...} ; 后漏掉了一个分号 ;

也就是说:

a.X = function x(){
   console.log("shouldn't be executed");
};

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