[关闭]
@mwumli 2016-03-27T13:14:01.000000Z 字数 1790 阅读 2437

IIFE、闭包和模块

前端 JavaScript


自执行匿名函数是 JavaScript 模块化的基础
这里先简单介绍自执行匿名函数,在讨论自执行匿名函数的好处,最好介绍怎么使用自执行匿名函数来使你的 JavaScript 代码模块化

IIFE

什么是 IIFE

IIFE, 即 Immediately-Invoked Function Expression, 立即调用的函数表达式
也就是俗称的 自执行匿名函数

关于 IIFE 的讨论这里不再提及, 有兴趣的话可以这两篇文章 :

  1. Immediately-Invoked Function Expression (IIFE)
  2. 知乎-JavaScript 匿名函数有哪几种执行方式?

一个简单常用的应用实例

一个自执行匿名函数的最简单、常见的应用实例 :

  1. (function() {
  2. console.log("IIFE");
  3. })()

IIFE 的好处

自执行匿名函数最大的好处 : 避免了全局作用域的污染

JavaScript 中函数被用来划分变量作用域
故自执行匿名函数可以控制变量的作用域, 阻止变量泄露到代码中的其他地方。
因此它不会向全局名字空间添加任何变量(通过 var 定义的变量), 这样也就避免了污染全局作用域

自执行匿名函数的这个好处对于我们创建 JavaScript 插件帮助巨大
因为作为一个好的 JavaScript 插件来说, 最大的问题就是避免污染了应用代码, 保持独立性

闭包

闭包是阻止垃圾回收器将变量从内存中移除的方法, 使得在创建变量的执行环境的外面能够访问到该变量

JavaScript 实现了自动释放内存的系统, 即垃圾回收器, 简称 gc (garbage collector)
当函数执行完毕的时候, gc 会将函数中所有创建的东西从内存中清理

但是如果函数执行完毕后, 依旧有函数可以访问这个变量, 那么这个变量就不会被释放, 这就是 闭包

  1. var person = (function () {
  2. var age = 23;
  3. return {
  4. getAge : function() {
  5. return age;
  6. }
  7. };
  8. })();
  9. console.log(person.getAge());

getAge 函数保存到 person 对象上, 一个闭包就创建了
闭包因保存函数而被创建, 在执行环境的外面, 可以动态访问 age 变量, 这就阻止 gc 将 age 变量从内存中移除

闭包通常的使用场景 和 this 对象有关, 比如下面这个场景 :

  1. var name = "Here is Global";
  2. var local = {
  3. name : "Here is Local",
  4. getNameFunction : function() {
  5. var that = this;
  6. return function(){
  7. console.log(that.name);
  8. console.log(this.name);
  9. }
  10. }
  11. }
  12. local.getNameFunction()();
  13. // 运行结果 :
  14. // Here is local
  15. // Here is Global

模块

模块就是实现特定功能的一组方法
只要把不同的函数(以及记录状态的变量)简单地放在一起,就算是一个模块。

但是一个优秀的模块应该保持自己的独立性, 避免自身的变量污染到应用代码, 而引起不必要的冲突
JavaScript 的自执行匿名函数的特性正恰好符合这个要求

JavaScript 的模块还依赖于闭包(closure), 因为使用闭包可以实现只暴露你想要暴露的接口, 一定程度上就为模块实现私有成员

所以简单的模块实现 :

  1. var module1 = (function(){
  2.     var _count = 0;
  3.     var m1 = function(){
  4.       //...
  5.     };
  6.     var m2 = function(){
  7.       //...
  8.     };
  9.     return {
  10.       m1 : m1,
  11.       m2 : m2
  12.     };
  13.   })();

如果一个模块很大,必须分成几个部分,或者一个模块需要继承另一个模块, 可以这样做 :

  1. var module1 = (function(mod){
  2.     mod.m3 = function () {
  3.      //...
  4.     };
  5.     
  6.     return mod;
  7.   })(module1);

如果一个模块需要引入外部的库, 比如 jquery, 可以这样做 :

  1. var module1 = (function ($) {
  2.     //...
  3.   })(jQuery);

关于模块的书写目前有三大规范可以遵循: CommonJS(Nodejs), AMD(RequireJS), CMD(Seajs)

这三大规范的区别在这里有简单的讨论 : http://www.cnblogs.com/dolphinX/p/4381855.html

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注