CMD&AMD
在ES6之前,社区已经有了一些模块化方法,最主要的是用于Node端的CMD和用于浏览器端的AMD。
CMD
在CMD中,有一个全局性方法require(),用于加载模块。假定有一个数学模块math.js,就可以像下面这样加载。
var math = require('math'); math.add(2,3); // 5
AMD
AMD也采用require()语句加载模块,但是不同于CommonJS,它要求两个参数:require([module], callback);
第一个参数[module],是一个数组,里面的成员就是要加载的模块;第二个参数callback,则是加载成功之后的回调函数。如果将前面的代码改写成AMD形式,就是下面这样:
require(['math'], function (math) { math.add(2, 3); });
导出
返回一个JSON
//app.js var app = { name:'app' sayName:function(name){ console.log(this.name) } } module.exports = app //使用 var app = require('./app.js'); app.sayName('hello');//hello
exports.xxx
//functions.js var func1 = function() { console.log("func1"); }; var func2 = function() { console.log("func2"); }; exports.function1 = func1; exports.function2 = func2; //使用 var functions = require("./functions"); functions.function1(); functions.function2();
两者的区别
CMD 推崇依赖就近,AMD 推崇依赖前置。看代码:
// CMD define(function(require, exports, module) { var a = require('./a') a.doSomething() // 此处略去 100 行 var b = require('./b') // 依赖可以就近书写 b.doSomething() // ... }) // AMD 默认推荐的是 define(['./a', './b'], function(a, b) { // 依赖必须一开始就写好 a.doSomething() // 此处略去 100 行 b.doSomething() ... })
import&export
import
import命令输入的变量都是只读的,因为它的本质是输入接口。也就是说,不允许在加载模块的脚本里面,改写接口。
// ES6模块 import { stat, exists, readFile } from 'fs';
export
如果你希望外部能够读取模块内部的某个变量,就必须使用export关键字输出该变量。
// profile.js export var firstName = 'Michael'; export var lastName = 'Jackson'; export var year = 1958; //or var firstName = 'Michael'; var lastName = 'Jackson'; var year = 1958; export { firstName, lastName, year };
export default
为了给用户提供方便,让他们不用阅读文档就能加载模块,就要用到export default命令,为模块指定默认输出。
// export-default.js export default function () { console.log('foo'); }
上面代码是一个模块文件export-default.js,它的默认输出是一个函数。其他模块加载该模块时,import命令可以为该匿名函数指定任意名字。
// import-default.js import customName from './export-default'; customName(); //
ES6模块与CommonJS模块的差异
- CommonJS模块输出的是一个值的拷贝,ES6模块输出的是值的引用
- CommonJS模块是运行时加载,ES6模块是编译时输出接口
第二个差异是因为 CommonJS 加载的是一个对象(即module.exports属性),该对象只有在脚本运行完才会生成。而 ES6 模块不是对象,它的对外接口只是一种静态定义,在代码静态解析阶段就会生成。
CommomJS
CommonJS 模块输出的是值的拷贝,也就是说,一旦输出一个值,模块内部的变化就影响不到这个值
// lib.js var counter = 3; function incCounter() { counter++; } module.exports = { counter: counter, incCounter: incCounter, }; // main.js var mod = require('./lib'); console.log(mod.counter); // 3 mod.incCounter(); console.log(mod.counter); // 3
ES6模块
ES6 的import有点像 Unix 系统的“符号连接”,原始值变了,import加载的值也会跟着变。因此,ES6 模块是动态引用,并且不会缓存值,模块里面的变量绑定其所在的模块。
// lib.js export let counter = 3; export function incCounter() { counter++; } // main.js import { counter, incCounter } from './lib'; console.log(counter); // 3 incCounter(); console.log(counter); // 4