以下是示例:
var f = function(x) {
alert(x)
}
(function() {
f(1)
}())
为什么
TypeError:f不是函数“?
答案 0 :(得分:12)
在您的示例中,f
不是函数。如果您更改示例,则为:
var f = function(x) {
alert(x)
};
(function() {
f(1)
}());
你违反automatic semicolon insertion(或缺乏)。
由于ASI规则,如果一行不以分号结尾,则解析器可以组合行。在您的情况下,var f = function
语句后缺少分号会导致解析器在f
初始化之前声明并立即调用该函数,并尝试将结果分配给f
:
var f = function(x) {
alert(x)
}(function() {
f(1)
}())
只需插入分号,就可以强制解析器中断两个语句,代码的行为与预期的一样。
解析器更喜欢将它们组合起来,因为它看到一个函数和看起来像是参数(由于前导括号,忽略了空格)。它调用刚声明的函数,然后调用f
,但f
尚未初始化,因此不是函数。
我在旧的Web应用程序中遇到了一个特别有趣的案例(在webpack和browserify存在之前组合文件):我们只是将JS文件按顺序放在一起,大多数都在IIFE模块中。一个脚本在其模块之后没有以分号结束,因此下一个模块在初始化第一个时作为参数传递。这是一个痛苦的发现,因为它发生在应用程序的早期,是一个单一的失踪半。
在这种情况下,通过在我们连接的文件之间添加注释,我们能够在不更改任何外部代码的情况下解决问题,但良好的做法是使用分号和换行符结束代码。它避免了这种罕见的空白错误。
答案 1 :(得分:6)
这是自动分号插入让你失望并且代码被解释为IIFE的情况:
true
这就是为什么var f = function(x) {
alert(x)
}(function() {
f(1)
}())
确实没有被定义的原因。
所以经验法则:永远不要用f
或(
开始。然后你可以安全地省略分号。