随着JavaScript代码复杂度的提高,从无模块化到现在的ES6模块化,有很大的变化,发展阶段如下:无模块化
->CommonJS规范
->AMD规范
->CMD规范
->ES6模块化
-
无模块化
JavaScript最初只需要实现简单的验证和提交表单,以及一些简单的JS交互效果,直接在HTML中通过script标签引入js文件或直接在script标签中添加相应JavaScript代码即可。
随着代码负责度的增加,需要引入多个JavaScript文件,特殊情况下还需要注意顺序,比如使用jQuery实现功能之前,必须先引入jQuery,顺序错误会导致报错。
优点:
- 有模块化的思想雏形,代码可读性相对于单JavaScript文件和直接在script标签中写JavaScript代码较好
缺点:
- 污染全局变量
- 依赖关系不明显,容易出错
-
CommonJS规范
-
node应用由模块组成,采用
CommonJS
规范 -
每个文件就是一个模块,有自己的作用域,每个文件里的变量、函数、类都是私有的,对其他文件不可见。
-
通过
exports
属性导出模块,通过require
加载模块//导出 var x = 5; var addX = function (value) { return value + x; }; module.exports.x = x; module.exports.addX = addX; //导入 var example = require('./example.js'); console.log(example.x); // 5 console.log(example.addX(1)); // 6
-
提问1:exports和module.exports的区别?
exports只是module.exports的引用,辅助后者添加内容,最终require引入的内容,始终是module.exports的,如果exports指向没有被改变,exports和module.exports指向的内容是一样的。建议使用commonJS规范时,统一使用module.exports导出,require导入
缺点:
- CommonJS规范时同步加载模块的,只有加载完成了,才会执行后面的操作,用于服务器编程不存在速度慢的问题,可是浏览器环境是从服务器加载模块,需要使用非同步加载模块,CommonJS规范不符合要求。
优点:
- 不污染全局变量
- 模块可以多次加载,但只会在第一次加载时运行一次,然后运行结果缓存,以后加载,直接读取缓存结果,要想模块再次运行,必须清除缓存
-
-
AMD规范
AMD规范的出现,解决了非同步加载模块的问题,允许使用回调函数,require.js采用的就是AMD规范。
-
定义模块
define(id,[depends],callback);
-
加载模块
require([module],callback);
-
兼容CommonJS规范
define(function (require, exports, module){ var someModule = require("someModule"); var anotherModule = require("anotherModule"); someModule.doTehAwesome(); anotherModule.doMoarAwesome(); exports.asplode = function (){ someModule.doTehAwesome(); anotherModule.doMoarAwesome(); }; });
注意:使用require.js时,必须提前加载该模块的所有依赖,才能使用,不能按需加载
缺点:
解决了浏览器环境异步加载的问题,可同步加载多个模块
优点:
不能按需加载依赖模块,必须提前加载
-
-
CMD规范
CMD规范的出现解决了,上述问题中按需加载的问题,
sea.js
使用的就是CMD规范,它和require.js
相比,最大的区别就是可按需加载模块,即模块的加载可以延迟执行。// AMD define(['./a', './b'], function(a, b) { // 依赖必须一开始就写好 a.doSomething() // 此处略去 100 行 b.doSomething() ... }); // CMD define(function(require, exports, module) { var a = require('./a') a.doSomething() // 此处略去 100 行 var b = require('./b') // 依赖可以就近书写 b.doSomething() // ... });
缺点:
同时解决了浏览器端异步加载和延迟加载模块的问题
优点:
依赖SPM打包,模块的加载逻辑偏重
-
ES6模块化
ES6的模块化规范才是真正的规范,
import
引入模块,export
导出模块,和前几个方案相比,功能更加强大,但目前ES6无法在浏览器中执行,所以需要使用babel
将import编译为广泛支持的require。在项目中应该统一使用import或require,import以后应该是主流方向,所以推荐使用import//导出示例 export default a; export a; export {a,b}; //function和class导出的正确写法 //写法1 function f(){} export {f}; //写法2 export function f() {}; //导入示例 import a from './xx.js'; import {a} from './xx.js'; import {a,b} from './xx.js';
提问2:export default 和 export的区别?
答:
-
export和export default均可导出常量、函数、文件、模块等
-
在一个文件或模块中,export、import可以有多个,export default仅有一个
-
通过export方式导出,在导入时要加{},export default不需要
-
export能直接导出变量表达式,export default不行
提问3:import和require的区别?
答:
import/export是ES6新规范;require/exports是CommonJS的一部分
区别:
- import/export比较灵活
- CommonJS和ES6 Module 输出都可以看成是一个具备多个属性或者方法的对象
- default 是ES6 Module所独有的关键字,export default 输出默认的接口对象,import from 'fs’可直接导入这个对象;
- ES6 Module中导入模块的属性或者方法是强绑定的,包括基础类型;而 CommonJS 则是普通的值传递或者引用传递。
-