Moeyua

講評世界

JavaScript 立即调用的函数表达式(IIFE)

发布于 # 技术文档

最近工作一直很闲,导师姐姐看我没事做就安排我看一下公司的项目,顺便让我画一份登陆的流程图来(摸鱼不好吗,流泪了)。

在项目里发现了一段没见过的函数写法,看着很奇怪:

(function (win, doc, c) {

  function login(options) {
      
    // JavaScript code

  }
  win.cpdailyLogin = login
})(window, document);

查了一下发现原来是立即调用的函数表达式(学完就忘),学的时候觉得这东西真的有人用吗,结果工作了发现还真的有人用,借此机会查阅了一些资料,顺便记录一下。

立即调用的函数表达式(IIFE) 其实也算是 JavaScript 的特色之一了,这么写的好处就在于不需要设置变量名,不用污染全局变量,而且在 IIFE 内部形成了一个单独的作用域,可以封装一些外部无法读取的私有变量。

根据 JavaScript 的语法,在函数名称后面跟一对圆括号()表示直接调用该函数,这个是学过 JS 的人都知道的,但是有时候我们需要在定义一个函数后立即对这个函数进行调用,例如:

function () {
  // some code
} ()

// SyntaxError: Unexpected token (

但是这种写法会报错,因为function这个关键字可以当作表达式和语句,上面这种写法就是语句,JavaScript 认为这是函数的定义,不应该在后面对函数进行调用,所以会报错。
为了避免这种歧义,JavaScript 规定:如果function关键字出现在一行的开头,一律都解释为语句。那么这样事情就简单了很多,既然出现在行首会被认为是函数的定义,那么只要function关键字不出现在行首不就行了。于是乎就有了我所看到的写法:将函数定义用括号包起来,或者是将他们一起包起来,这样行首就不是function关键字了,而是括号,这样一来就解决了问题。

// 方法 1
(function () {
  // some code
})();

// 方法 2
(function () {
  // some code
} () );

这里的分号是一定需要的,否则第二行会被解析为第一行的参数,会产生错误。

顺着这种思路,有很多种方法都可以实现,但原理和效果都是一样的。