【发布时间】:2016-02-04 21:31:20
【问题描述】:
示例如下:
var f = function(x) {
alert(x)
}
(function() {
f(1)
}())
为什么
TypeError: f is not a function"?
【问题讨论】:
-
感谢您的编辑!
标签: javascript function
示例如下:
var f = function(x) {
alert(x)
}
(function() {
f(1)
}())
为什么
TypeError: f is not a function"?
【问题讨论】:
标签: javascript function
在您的示例中,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 模块中。一个脚本在其模块后没有以分号结尾,因此在初始化第一个模块时,下一个模块被作为参数传递。很难找到,因为它发生在应用程序的早期并且是一个缺失的半成品。
在这种情况下,我们能够通过在要连接的文件之间添加 cmets 来解决问题,而无需更改任何外部代码,但好的做法是使用分号和换行符结束您的代码。它避免了像这样的各种罕见的空白错误。
【讨论】:
这是自动分号插入让您失望并且代码被解释为 IIFE 的情况:
var f = function(x) {
alert(x)
}(function() {
f(1)
}())
这就是为什么 f 确实没有定义的原因。
所以经验法则:永远不要以( 或[ 开头。然后你可以放心地省略分号。
【讨论】:
;(function () { ... }())。