JS笔记 - 模块化
JavaScript 模块指的是一段可复用的,独立的代码。他们通常都有特定的功能,能在整个代码系统里被引进或删除。
模块通常是独立的——与其他代码解耦,因此方便修改。这也提高了代码的可读性和可维护性。模块化在使部分代码保持私有,仅暴露公共部分的的同时,还解决了命名空间模糊性的问题。
CommonJS
CommonJS 规范需要使用两个关键字require
和exports
。
require:用来声明导入某个模块,可以传入具体的模块路径也可以传入模块名。当 require 某个模块名时,Nodejs 就会在 node_modules 文件夹中查找对应的模块;
exports:用来声明当前 js 文件要导出的内容。
//------ store/customer.js 文件------
exports = function(){
return customers.get('store');
}
//------ payments.js 文件------
var customerStore = require('store/customer');
Nodejs 遵守了 CommonJS 的规范,但是它使用的是module.exports
。
//store/customer.js 文件
function customerStore(){
return customers.get('store');
}
modules.exports = customerStore;
缺点:
- 只支持同步加载,不支持异步,必须等待加载完所有文件后才能运行。
- 只有对象能被导出(函数也是特殊的对象),即无法导出变量/常量。
- CommonJS 规范不能直接在浏览器的js环境下使用 ( 必须使用 Webpack 等工具转译处理)
注意事项:
require第一次加载某个模块时,Node会缓存该模块。以后再加载该模块,就直接从缓存取出该模块。
//a.js module.exports = { name: '123', age: 27 } //b.js let obj1 = require('./a.js') console.log(obj1) // {name:'123',age:27} obj1.name = 'abc' let obj2 = require('./a.js') console.log(obj2) // {name:'abc',age:27} console.log(obj1) // {name:'abc',age:27}
CommonJS模块的加载机制是,一旦输出一个值,模块内部的变化就影响不到这个值,改造了一下上面的例子,可以看到调用模块内部的 change 方法时并不会改变输出的值。
//a.js var name = "123"; function change() { name = "456"; } module.exports = { name: name, age: 27, change: change }; //b.js let obj1 = require("./a.js"); console.log(obj1); // {name:'123',age:27} obj1.change(); let obj2 = require("./a.js"); console.log(obj2); // {name:'123',age:27} console.log(obj1); // {name:'123',age:27}
AMD
AMD 解决了 CommonJS 无法直接在浏览器上使用的问题,并且支持了异步加载。
AMD 的设计初衷就是给浏览器环境使用的,可以加快页面启动时间,而且这些模块导出内容可以是对象、函数、构造器、字符串、JSON等等。支持多模块多文件。
requirejs 实现了 AMD 的规范,它使用require
和defined
两个 API
// index.js
// 调用模块
require(['moduleA', 'moduleB', 'moduleC'], function (moduleA, moduleB, moduleC){
// some code here
// 可以在这里编写模块加载后的代码
});
// require()函数接受两个参数:
// 第一个参数是一个数组,表示所依赖的模块['moduleA', 'moduleB', 'moduleC']
// 第二个参数是一个回调函数,当前面指定的模块都加载成功后,它将被调用
// 注意['moduleA', 'moduleB', 'moduleC']这里面的三个模块与index.js在同一个目录
// moduleA.js
// 创建模块
define(function (){
var add = function (x,y){
return x+y;
};
return {
add: add
};
});
// index.js
require(['moduleA'], function (moduleA){
console.log(moduleA)
//moduleA就是moduleA.js模块传入的函数执行后返回的对象{add:function}
});
ES6
ES6 模块分为两部分:export 和 import
export语句输出的接口,与其对应的值是动态绑定关系,即通过该接口,可以取到模块内部实时的值
此外还提供了按需加载的功能,能够动态引入模块
button.addEventListener('click', event => {
import('./dialogBox.js')
.then(dialogBox => {
dialogBox.open();
})
.catch(error => {
/* Error handling */
})
});
ES6 和 CommonJS 之间的区别:
- CommonJS 模块输出的是一个值的拷贝,ES6 模块输出的是值的引用
- CommonJS 模块是运行时加载,ES6 模块是编译时输出接口。
- CommonJS 模块的
require()
是同步加载模块,ES6 模块的import
命令是异步加载,有一个独立的模块依赖的解析阶段
JS笔记 - 模块化