未捕获的类型错误: (中间值)(...) 不是函数使分号规则变得简单

2022-08-30 01:15:00

当我在闭包中将js逻辑编写为单个js文件时,一切正常,例如:

(function(win){
   //main logic here
   win.expose1 = ....
   win.expose2 = ....
})(window)

但是当我尝试在同一个js文件中的闭包之前插入日志记录替代函数时,

 window.Glog = function(msg){
     console.log(msg)
 }
 // this was added before the main closure.

 (function(win){
   //the former closure that contains the main javascript logic;
 })(window)

它抱怨有一个TypeError:

Uncaught TypeError: (intermediate value)(...) is not a function

我做错了什么?


答案 1

该错误是由于第三行缺少分号导致的:

window.Glog = function(msg) {
  console.log(msg);
}; // <--- Add this semicolon

(function(win) {
  // ...
})(window);

ECMAScript 规范具有用于自动插入分号的特定规则,但是在这种情况下,分号不会自动插入,因为从下一行开始的括号表达式可以解释为函数调用的参数列表。

这意味着如果没有该分号,匿名函数将以函数作为参数进行调用,随后尝试调用返回的任何内容。window.Glogmsg(window)

代码是这样解释的:

window.Glog = function(msg) {
  console.log(msg);
}(function(win) {
  // ...
})(window);

答案 2

使分号规则变得简单

每一行以 、 、 ' 或任何算术运算符开头的行,如果要将其解释为自己的行,则必须以分号开头 ~ 否则,它可能会意外地与前一行组合。所有其他换行符都有隐式分号。([

就是这样。做。

  • 请注意,/, +, - 是您要执行此操作的唯一有效运算符。你永远不会希望一行以“*”开头,因为它是一个二元运算符,在行的开头永远不会有意义。

  • 执行此操作时,应将分号放在行的开头。您不应尝试通过在一行添加分号来“修复”问题,否则代码的任何重新排序或移动都可能导致问题再次出现。许多其他答案(包括热门答案)都提出了这个建议,但这不是一个好的做法。


为什么这些特定字符需要首字母分号?

请考虑以下事项:

func()
;[0].concat(myarr).forEach(func)
;(myarr).forEach(func)
;`hello`.forEach(func)
;/hello/.exec(str)
;+0
;-0

通过遵循给定的规则,您可以防止上述代码被重新解释为

func()[0].concat(myarr).forEach(func)(myarr).forEach(func)`hello`.forEach(func)/hello/.forEach(func)+0-0

附加说明

提到将会发生什么:括号将索引,括号将被视为函数参数。反引号将转换为标记的模板,正则表达式将转换为除法,显式 +/- 有符号整数将转换为加/减运算符。

当然,你可以通过在每个换行符的末尾添加一个分号来避免这种情况,但不要相信这样做可以让你像C程序员一样编码。由于当您以分号结束一行时,Javascript可能会代表您隐式添加一个分号,违背您的意愿。因此,请记住以下语句:

return       // Implicit semicolon, will return undefined.
    (1+2);

i        // Implicit semicolon on this line
   ++;   // But, if you really intended "i++;"
         // and you actually wrote it like this,
         // you need help.

上述情况将碰巧返回/继续/中断/++/--.任何 linter 都会捕获前一种情况与死代码,或后一种情况与 ++/--语法错误。

最后,如果您希望文件串联起作用,请确保每个文件都以分号结尾。如果您使用的是捆绑程序(推荐),它应该自动执行此操作。