在node.js(Windows)中对IIFE的奇怪观察

以下行为是否适用于nodejs? 它看起来对我来说是越野车。 如果不是我错过了什么?

var abc = function(){ console.log("hello"); } (function(){ console.log("welcome"); })(); 

我得到以下例外

 TypeError: undefined is not a function at Object.<anonymous> (C:\node\main.js:8:3) at Module._compile (module.js:460:26) at Object.Module._extensions..js (module.js:478:10) at Module.load (module.js:355:32) at Function.Module._load (module.js:310:12) at Function.Module.runMain (module.js:501:10) at startup (node.js:129:16) at node.js:814:3 

如果我改变代码

 var abc = function(){ console.log("hello"); } (function(){ console.log("welcome"); }()); 

它产生

欢迎你好

我不得不相信节点parsing错误地假定嵌套的IIFE(function(){…})())首先被执行,而IIFE的和(outer)会触发它上面的函数定义的执行(如果我引入一个abc定义和IIFE之间的注释行)。

这不仅仅是一个node.js问题。 你会在浏览器中得到相同的错误。 正如其他人所提到的,错误是第一个函数中缺less的分号。 但是发生了什么事?

那么首先让我们来解释一下IIFE究竟是什么。 你可能知道这个语法:

 (function(){})(); 

但这不是IIFE的唯一语法。 IIFE立即被调用函数expression式。 所以它在声明之后立即调用一个函数expression式。

那么,什么是函数expression式? 它只是一个在expression式上下文中声明的函数。 在expression式上下文中求值的一种方法是使用大括号操作符:( () 。 在这里,大括号运算符实际上是math中相同的大括号运算符:它强制math运算的优先级。

所以在这个大括号:

 (function(){}) 

这个意思完全一样:

 (1+1) 

它告诉解释器,它里面的代码是一个返回值的expression式。 所以这就是expression式上下文的含义 – 任何你可以做计算来返回值的地方。

还有其他地方的语言解释为expression上下文。 其中之一就是在操作员之后。 比如说! 运算符或-运算符(使数字为负数)。 所以,就像你可以写:

 -12 + 5 

你也可以这样写一个IIFE:

 -function(){}() 

javascript解释为expression式上下文的另一个地方就是=符号右边的所有内容。 例如:

 var x = 12 + 5; 

这意味着,你可以这样写一个IIFE:

 var x = function(){}(); 

这是什么导致您的代码中的问题。 基本上,JavaScript解释你的代码是这样的:

 var abc = function(){ console.log("hello"); }(function(){console.log("welcome")})(); 

也就是说,你的第一个函数被视为一个IIFE,它通过传递你的第二个函数作为参数来调用,并试图调用第一个函数的返回值(这是未定义的,因为你不会返回任何东西,只是logging“你好“)。

换句话说,如果我们把它分解,就是这样做的:

 function first_function () { console.log('hello') } function second_function () { console.log('world') } var temp = first_function(second_function); var abc = temp; // it errors here because temp is undefined 

教训是,函数声明后不需要分号,但在函数expression式之后需要分号。

其次,没有多less有用的教训:IIFE有多种方式。

缺less分号是导致问题的原因。

 var abc = function(){ console.log("hello"); }; // missing semicolon! (function(){ console.log("welcome"); })();