模块化开发
一个模块是实现一个特定功能的一组方法。
在最开始的时候,js 只实现一些简单的功能,所以并没有模块的概念,但随着程序越来越复杂,代码的模块化开发变得越来越重要。
由于函数具有独立作用域的特点,最原始的写法是使用函数来作为模块,几个函数作为一个模块,但是这种方式容易造成全局变量的污染,并且模块间没有联系。
后面提出了对象写法,通过将函数作为一个对象的方法来实现,这样解决了直接使用函数作为模块的一些缺点,但是这种办法会暴露所有的所有的模块成员,外部代码可以修改内部属性的值。
现在最常用的是立即执行函数的写法,通过利用闭包来实现模块私有作用域的建立,同时不会对全局作用域造成污染。
模块加载方案
- CommonJS 方案
通过 require 来引入模块,是服务器端的解决方案,它是以同步的方式来引入模块的。
因为在服务端文件都存储在本地磁盘,所以读取非常快,所以以同步的方式加载没有问题。
但如果是在浏览器端,由于模块的加载是使用网络请求,因此使用异步加载的方式更加合适。
模块输出的是一个值的拷贝,模块内部的变化就影响不到这个值。
运行时加载,即在输入时是先加载整个模块,生成一个对象,然后再从这个对象上面读取方法
AMD 方案
采用异步加载的方式来加载模块,模块的加载不影响后面语句的执行,所有依赖这个模块的语句都定义在一个回调函数里,等到加载完成后再执行回调函数。
require.js 实现了 AMD 规范。CMD 方案
解决异步模块加载的问题,sea.js 实现了 CMD 规范。
AMD 和 CMD 规范的区别?
模块定义时对依赖的处理不同
AMD推崇依赖前置,在定义模块的时候就要声明其依赖的模块。
而 CMD 推崇就近依赖,只有在用到某个模块的时候再去 require。对依赖模块的执行时机的处理不同
AMD 在依赖模块加载完成后就直接执行依赖模块,依赖模块的执行顺序和我们书写的顺序不一定一致。
而 CMD在依赖模块加载完成后并不执行,只是下载而已,等到所有的依赖模块都加载好后,进入回调函数逻辑,遇到 require 语句的时候才执行对应的模块,这样模块的执行顺序就和我们书写的顺序保持一致了
// CMD
define(function(require, exports, module) {
var a = require("./a");
a.doSomething();
//...
var b = require("./b"); // 依赖可以就近书写
b.doSomething();
// ...
});
// AMD 默认推荐
define(["./a", "./b"], function(a, b) {
// 依赖必须一开始就写好
a.doSomething();
//...
b.doSomething();
// ...
});
- ES6
使用 import 和 export 的形式来导入导出模块
模块输出的是值的引用
编译时输出接口加载