浅谈JS模块化和闭包

最近有被问到require import的区别模块间如果相互引用会发生什么等问题。

思考了一会,对于模块间相互引用,应该内部进行了处理,只是觉得应该,说不出一二三。而require则只说出是值复制,而import是引用。

发现自己在模块化方面了解的不多,赶紧搜资料恶补起来,并通过曾经的学习经历+恶补经历在这里记录下来。

还记得一开始学习JS的时候,看的是Blue老师的教学视频(非常感谢Blue老师的优秀教程)。

当时写代码直接是:

1
2
3
4
5
6
7
8
9
// a.js
function move() {
// some code
}

// b.js
function init() {
move();
}

然后在html中通过顺序引入进来:

1
2
<script src="a.js"></script>
<script src="b.js"></script>

这样在当时按着视频教学学的时候,因为文件不多(基本是单文件),所以也没有出现什么问题(bug)。

但随着文件的增多,甚至是协同开发,那这样子非常容易发生变量的冲突,例如在b.js中写入function move,导致覆盖a.js中的move方法,因为这样污染了全局。

后来学习了jQuery,在每个文件中使用自执行函数(IIFE),并暴露出当前文件的一个变量,看下面代码:

1
2
3
4
5
6
7
var ModuleA = (function($) {
return {
move: function() {
// some code
}
}
})(jQuery);

这样规避了move方法的重名,每个文件只会暴露一个模块名到全局,但是这样子只是并没有根治全局污染,不过好好管理应该是没有什么太大的问题。

这里引申一下,像上面的自执行函数,其实是一个匿名闭包,而闭包又会牵扯到垃圾回收。

闭包及垃圾回收机制

闭包

简要

  1. 函数foo中如果声明了函数bar和baz,在foo函数执行退出后,不会销毁函数bar和baz(不会销毁foo定义的局部变量),并允许我们返回到外面,通过返回的变量来访问。并且函数bar和baz中还可以访问到foo中声明的其他变量

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    function foo() {
    function bar() {}
    function baz() {}
    return {
    bar: bar,
    baz: baz,
    }
    }

    var f = foo(); // 执行结束,不会销毁bar和baz
    f.bar(); // 通过变量f访问
  2. 闭包可作为函数参数传递和结果返回,并且JS是事件驱动的,这应该也算是闭包的意义吧

未完

推荐文章