【问题标题】:Why "TypeError: f is not a function"?为什么“TypeError:f 不是函数”?
【发布时间】:2016-02-04 21:31:20
【问题描述】:

示例如下:

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

(function() {
   f(1)
}())

为什么

TypeError: f is not a function"?

【问题讨论】:

标签: javascript function


【解决方案1】:

在您的示例中,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 来解决问题,而无需更改任何外部代码,但好的做法是使用分号和换行符结束您的代码。它避免了像这样的各种罕见的空白错误。

【讨论】:

    【解决方案2】:

    这是自动分号插入让您失望并且代码被解释为 IIFE 的情况:

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

    这就是为什么 f 确实没有定义的原因。

    所以经验法则:永远不要以([ 开头。然后你可以放心地省略分号。

    【讨论】:

    • 用括号开始一行对于 IIFE 来说很常见。我认为只在 括号和大括号之后使用分号可能会更好。
    • @ssube 我知道,但这是省略分号的唯一可能问题。 IIFE 可以以附加分号开头:;(function () { ... }())
    猜你喜欢
    • 2021-09-09
    • 2019-10-12
    • 2019-05-25
    • 2021-01-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多