1. “立即调用的函数表达式”(IIFE Immediately-Invoked Function Expression)
    2. 立即执行函数表达式,通常用于立即执行匿名函数
    3. 立即执行函数可实现独立作用域,以此来避免污染全局变量

    根据 JavaScript 的语法,圆括号()跟在函数名之后,表示调用该函数。比如,print()就表示调用print函数。

    有时,我们需要在定义函数之后,立即调用该函数。这时,你不能在函数的定义之后加上圆括号,这会产生语法错误。

    1. function(){ /* code */ }();
    2. // SyntaxError: Unexpected token (

    产生这个错误的原因是,function这个关键字既可以当作语句,也可以当作表达式。

    1. // 语句
    2. function f() {}
    3. // 表达式
    4. var f = function f() {}

    当作表达式时,函数可以定义后直接加圆括号调用。

    1. var f = function f(){ return 1}();
    2. f // 1

    上面的代码中,函数定义后直接加圆括号调用,没有报错。原因就是function作为表达式,引擎就把函数定义当作一个值。这种情况下,就不会报错。

    为了避免解析的歧义,JavaScript 规定,如果function关键字出现在行首,一律解释成语句。因此,引擎看到行首是function关键字之后,认为这一段都是函数的定义,不应该以圆括号结尾,所以就报错了。

    函数定义后立即调用的解决方法,就是不要让function出现在行首,让引擎将其理解成一个表达式。最简单的处理,就是将其放在一个圆括号里面。

    1. (function(){ /* code */ }());
    2. // 或者
    3. (function(){ /* code */ })();

    上面两种写法都是以圆括号开头,引擎就会认为后面跟的是一个表达式,而不是函数定义语句,所以就避免了错误。这就叫做“立即调用的函数表达式”(Immediately-Invoked Function Expression),简称 IIFE

    注意,上面两种写法最后的分号都是必须的。如果省略分号,遇到连着两个 IIFE,可能就会报错。

    1. // 报错
    2. (function(){ /* code */ }())
    3. (function(){ /* code */ }())

    上面代码的两行之间没有分号,JavaScript 会将它们连在一起解释,将第二行解释为第一行的参数。

    推而广之,任何让解释器以表达式来处理函数定义的方法,都能产生同样的效果,比如下面三种写法。

    1. var i = function(){ return 10; }();
    2. true && function(){ /* code */ }();
    3. 0, function(){ /* code */ }();

    甚至像下面这样写,也是可以的。

    1. !function () { /* code */ }();
    2. ~function () { /* code */ }();
    3. -function () { /* code */ }();
    4. +function () { /* code */ }();

    通常情况下,只对匿名函数使用这种“立即执行的函数表达式”。它的目的有两个:

    1. 一是不必为函数命名,避免了污染全局变量
    2. 二是 IIFE 内部形成了一个单独的作用域,可以封装一些外部无法读取的私有变量
    1. // 写法一
    2. var tmp = newData;
    3. processData(tmp);
    4. storeData(tmp);
    5. // 写法二
    6. (function () {
    7. var tmp = newData;
    8. processData(tmp);
    9. storeData(tmp);
    10. }());

    上面代码中,写法二比写法一更好,因为完全避免了污染全局变量。