lodash源码解读之模块化的基础——IIFE

IIFE(Immediately Invoked Function Expression),中文一般翻译为匿名立即执行函数

IIFE详解

构成

IIFE包含两部分。
第一部分是一个匿名函数,它包裹在分组操作符()中,拥有独立的词法作用域。
第二部分是再一次使用分组操作符(),创建一个立即执行函数表达式。Javascript引擎到此将立即执行函数。
大体结构如下所示:

1
2
3
;(function(){
// code
})();

优点

  • 匿名函数中的变量和方法,不能从外部访问
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    (function () { 
    var name = 'wall';

    function sayHello(){
    console.log('hello');
    }
    })();
    // 外部不能访问变量 name 和方法 sayHello
    name // undefined
    sayHello() // sayHello is not defined

因为匿名函数有自己独立的词法作用域,所以会产生这种现象。

  • 匿名函数中可以正常访问更高词法作用域中的变量和方法
1
2
3
4
5
6
// 浏览器环境下
var name = 'wall';

(function(){
console.log(name); // 在控制台正常输出`wall`
})();

所以,IIFE并不是双向封闭的一个模块。模块内部可以有自己的私有方法和私有变量,也可以正常使用外部环境的变量和方法。

其他表现形式

1
2
3
4
5
6
7
8
9
10
11
!function(){

}();

+function(){

}();

(function(){

}());

本质上,都是先将匿名函数转变为可执行的表达式,然后再用分组操作符执行。

IIFE在lodash中的应用

先上源码:

1
2
3
;(function(){
// code
}.call(this))();

第一个;的作用

工具库的源码,一般都是;开始。为什么要以这个符号作为开始,其实别有深意。

  • 第一个涉及到的是概念:语句

    语句:是构成程序的基本单位,一条语句完成某种特定的操作。一般语句以分号;结束。

  • 另一个涉及到的是代码的优化手段:压缩合并
    在前端的铁器时代,YaHoo出了一个著名的压缩代码工具——YUI Compressor。它的作用之一,就是将多个js文件源码,合并到一起,变成一个新文件。以此来减少页面加载时的HTTP请求数。
    多个js文件压缩,总不免会出现黑天鹅,比如以下这种:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    // a.js
    function say(){
    // code
    }

    // b.js
    (function(){
    // code
    })();

    // a.js和b.js合并成c.js
    // c.js
    function say(){
    // code
    }(function(){
    // code
    })();

JavaScript引擎,解析c.js文件时,误将say方法进行执行,导致不可思议的事情发生。
而加上分号之后,则可以杜绝这种情况。

call的作用

call的使用,是为了显式指定当前匿名函数的上下文(context),由引用该工具库的环境所决定。

1
2
3
4
5
6
7
8
9
10
11
function Foo(){
(function(){
console.log(this); //Foo
}).call(this);

(function(){
console.log(this); //undefined in strict or global
})();
}

var test = new Foo;

参考

  1. MDN术语表-IIFE
  2. Why write “.call(this)” at the end of an javascript anonymous function?

关注我的项目(有帮助到你的话,麻烦点个star)

GitHub地址:lodash源码解读