就是下面这样的的代码:
(function foo() {
  console.log("Hello!");
})();关于 IIFE 书写方式
第一种情况:
function(){ /* code */ }(); // SyntaxError: Unexpected token (解释:JavaScript 在解析代码时,当遇到function关键字时,会默认把它当做一个函数声明,而不是函数表达式,如果没有把它显式的写成函数表达式,就报错,因为函数声明需要一个函数名。上面的报错是因为没有函数名(第一个左括号)。
第二种情况:
function foo(){ /* code */ }(); // SyntaxError: Unexpected token )解释:在表达式后面加括号表示执行;此外,在函数声明一个语句,在语句后面加括号可等价为:
function foo(){ /* code */ }
(); // SyntaxError: Unexpected token )相当于声明了函数 foo,后面进行()的表达式操作。()表示分组操作符,内部表达式不能为空,所以报错,上面的报错是因为分组操作符内为空的错误。
第三种情况:
(function() {
  /* code */
})();为什么这样就能立即执行并且不报错呢?因为在 javascript 里,括号内部不能包含语句,当解析器对代码进行解释的时候,先碰到了(),然后碰到 function 关键字就会自动将()里面的代码识别为函数表达式而不是函数声明。
因此,也可以这么写:
(function() {
  /* code */
})();此外,只要功能类似于()将语句转化为表达式的方式都能用于 IIFE,例如下面的写法都会生效:
false ||
  (function() {
    console.log("hello");
  })();
true &&
  (function() {
    console.log("hello");
  })();
"anything",
  (function() {
    console.log("hello");
  })();
~(function() {
  console.log("hello");
})();
!(function() {
  console.log("hello");
})() +
  (function() {
    console.log("hello");
  })() -
  (function() {
    console.log("hello");
  })();
~(function() {
  console.log("hello");
})(); // 变种第四种情况:
var i = (function() {
  return 10;
})();这样的写法把fucntion当做函数表达式,可以不加(),但是为了增加代码可读性,建议加上。
和闭包的配合
1. 保存函数内部变量状态
下面代码并不会像你想象那样的执行,因为i的值没有被锁住,当我们点击链接的时候,其实 for 循环已经执行完了,于是在点击的时候 i 的值其实已经是 elems.length 了。
var elems = document.getElementsByTagName("a");
for (var i = 0; i < elems.length; i++) {
  elems[i].addEventListener(
    "click",
    function(e) {
      e.preventDefault();
      alert("I am link #" + i);
    },
    "false"
  );
}这样改写:
var elems = document.getElementsByTagName("a");
for (var i = 0; i < elems.length; i++) {
  (function(i) {
    // 其实代码中的 i 和外面的 i 是在不同的作用域里完全不同,比如:
    elems[i].addEventListener(
      "click",
      function(e) {
        e.preventDefault();
        console.log("I am link #" + i);
      },
      "false"
    );
  })(i);
}IIFE 代码中的i和外面的i是在不同的作用域里,完全不同的两个值,只是名字一样。
2. 局部变量、模块化
立即执行函数在模块化中也大有用处。用立即执行函数处理模块化可以减少全局变量造成的空间污染,构造更多的私有变量。
// 创建一个立即执行的匿名函数
// 该函数返回一个对象,包含你要暴露的属性
// 如下代码如果不使用立即执行函数,就会多一个属性i
// 如果有了属性i,我们就能调用counter.i改变i的值
// 对我们来说这种不确定的因素越少越好
var counter = (function() {
  var i = 0;
  return {
    get: function() {
      return i;
    },
    set: function(val) {
      i = val;
    },
    increment: function() {
      return ++i;
    }
  };
})();
// counter其实是一个对象
counter.get(); // 0
counter.set(3);
counter.increment(); // 4
counter.increment(); // 5
counter.i; // undefined i并不是counter的属性
i; // ReferenceError: i is not defined (函数内部的是局部变量)总结
- 能转化为函数表达式的操作都能构造 IIFE
 - IIFE 和普通函数类似,可以传参,有返回值
 - IIFE 可以制造局部变量,用于模块化
 
参考
- 本文作者:烈风裘
 - 本文题目:IIFE立即执行函数
 - 本文链接:https://xiangst0816.github.io/blog/IIFE-li-ji-zhi-hang-xing-han-shu-shuo/
 - 版权声明:本博客所有文章除特别声明外,均采用CC BY-NC-SA 3.0 许可协议。转载请注明出处!