为什么"TypeError:f不是函数"?

Jim*_*ton 3 javascript function

这是一个例子:

var f = function(x) {
   alert(x)
}

(function() {
   f(1)
}())
Run Code Online (Sandbox Code Playgroud)

为什么

TypeError:f不是函数"?

ssu*_*ube 12

在您的示例中,f不是函数.如果您更改示例,则为:

var f = function(x) {
   alert(x)
};

(function() {
   f(1)
}());
Run Code Online (Sandbox Code Playgroud)

你已经与自动分号插入(或缺乏分号)相冲突.

由于ASI规则,如果一行不以分号结尾,则解析器可以组合行.在您的情况下,var f = function语句之后缺少分号会导致解析器f在初始化之前声明并立即调用该函数,并尝试将结果分配给f:

var f = function(x) {
   alert(x)
}(function() {
   f(1)
}())
Run Code Online (Sandbox Code Playgroud)

通过简单地插入分号,您可以强制解析器中断两个语句,并且代码的行为与您期望的一样.

解析器更喜欢将它们组合起来,因为它看到了一个函数和看起来像是参数(由于前导括号,忽略了空格).它调用刚声明的函数,然后调用f,但f尚未初始化,因此不是函数.

我在一个旧的Web应用程序中遇到了一个特别有趣的案例(在webpack和browserify存在之前组合文件):我们只是将JS文件按顺序放在一起,大多数都在IIFE模块中.一个脚本在其模块之后没有以分号结束,因此下一个模块在初始化第一个时作为参数传递.这是一个痛苦的发现,因为它发生在应用程序的早期,是一个单一的失踪半.

在这种情况下,通过在我们连接的文件之间添加注释,我们能够在不更改任何外部代码的情况下解决问题,但良好的做法是使用分号和换行符结束代码.它避免了像这样的所有罕见的空白错误.


dfs*_*fsq 6

在这种情况下,自动分号插入会让您失望并且代码被解释为IIFE:

var f = function(x) {
   alert(x)
}(function() {
   f(1)
}())
Run Code Online (Sandbox Code Playgroud)

所以这就是为什么f确实没有定义.

所以经验法则:永远不要用(或开始[.然后你可以安全地省略分号.

  • 对于IIFE而言,开始使用parens是很常见的.我认为在*parens和braces之后使用分号*可能更好. (2认同)