Nodejs 少了个分号,(function () { /* ... */ }(); 竟然报错

Nodejs 少了个分号,(function () { /* … */ }(); 竟然报错

刚才发现了一个很奇怪的问题: 在定义带花括号的变量时(比如function () {} 或者对象{}),其后面跟一个这样的匿名函数竟然会报错:

var a = {}
(function () {
  console.log('OK');
})();

出错信息:

node.js:201
        throw e; // process.nextTick error, or 'error' event on first tick
              ^
TypeError: object is not a function
    at Object.CALL_NON_FUNCTION (native)
    at Object.<anonymous> (f:\github\Liquid.js\test\b.js:2:10)
    at Module._compile (module.js:441:26)
    at Object..js (module.js:459:10)
    at Module.load (module.js:348:31)
    at Function._load (module.js:308:12)
    at Array.0 (module.js:479:10)
    at EventEmitter._tickCallback (node.js:192:40)

加了个分号就正常了:

var a = {};
(function () {
  console.log('OK');
})();

求大神们解释


9 回复

Node.js 少了个分号,(function () { /* ... */ }(); 竟然报错

在编写 JavaScript 代码时,特别是在使用 Node.js 进行开发时,有时会遇到一些看似奇怪的问题。例如,在定义带花括号的对象时,如果紧接着一个立即执行函数表达式(IIFE),可能会导致语法错误。

问题描述

考虑以下代码片段:

var a = {}
(function () {
  console.log('OK');
})();

这段代码会抛出一个错误:

node.js:201
        throw e; // process.nextTick error, or 'error' event on first tick
              ^
TypeError: object is not a function
    ...

原因分析

这个问题的根本原因在于 JavaScript 的自动分号插入(Automatic Semicolon Insertion, ASI)机制。当 JavaScript 解释器解析到 } 结束对象字面量时,它会认为对象定义已经结束,并且接下来的 (function () { ... })() 是一个单独的语句。然而,由于缺少分号,解释器将这两部分连接在一起,结果导致错误。

具体来说,JavaScript 解释器会将代码解释为:

var a = {}(function () {
  console.log('OK');
})();

这里 a 被视为一个函数调用,而 {} 显然是一个对象,不是函数,因此抛出了 TypeError

解决方案

解决这个问题的最简单方法是在对象定义后添加一个分号,以明确表示对象定义已经结束:

var a = {};
(function () {
  console.log('OK');
})();

这样,JavaScript 解释器就能正确地识别对象定义和 IIFE 分别作为两个独立的语句,从而避免了错误。

示例代码

以下是修正后的代码示例:

var a = {};  // 添加分号
(function () {
  console.log('OK');
})();

通过上述修改,代码可以顺利运行,输出 “OK”。

总结

为了避免类似的语法错误,在编写 JavaScript 代码时,尤其是在对象定义之后紧接着立即执行函数表达式时,应确保在对象定义后添加分号。这不仅有助于避免语法错误,还能提高代码的可读性和可维护性。


a = {}
(function() {})()

等价于

a = {}(function(){})();

这里解释器试图去将{}当作一个函数去调用,所以会出错。

关于分号解析规则可以参考 ecma-262 标准中的第 7.9.1 节——Rules of Automatic Semicolon Insertion

现在学习JavaScript中,其中一个头痛就是在(函数)哪加分号哪里不加…

表达式后面加分号,定义后面不需要;

比如

function test(){ }

这个不需要

但是如果这样

var a = function test(){}; 那么就要加分号,否则

var a = function(foo){return foo;}

(1);

console.log(a) // 1

学习了。这个自动加分号规则还真复杂。

不推荐不加分号。

学习了

前端最基本的规范

在JavaScript中,解析器会自动插入分号(Automatic Semicolon Insertion, ASI)来处理某些情况。但在一些特殊情况下,ASI的行为可能会导致代码出现意料之外的错误。

在你的例子中,var a = {} 这行代码会被解析为 {} 对象的定义,而不是空对象。然后紧随其后的 (function () { ... })() 被解析为尝试调用一个对象,这显然是非法的操作,因此会抛出 TypeError

解决方法是在 var a = {} 后面加上分号,明确告诉解析器这两行是独立的语句:

var a = {};
(function () {
  console.log('OK');
})();

这样,解析器会正确地将 var a = {} 解释为空对象的声明,并将 (function () { ... })() 解释为立即执行函数表达式(IIFE)。

回到顶部