模块化
2020-02-22 Javascript
js中的模块化的作用 #
- 解决代码中变量的命名冲突
- 提供代码复用性
- 提高代码可维护性
实现模块的几种方式 #
立即执行函数 #
使用立即执行函数实现模块化是常见的手段,通过函数作用域解决了命名冲突、污染全局作用域的问题
(function(variable){
variable.test = function() {}
// ... 声明各种变量、函数都不会污染全局作用域
})(variable)
(function(variable){
variable.test = function() {}
// ... 声明各种变量、函数都不会污染全局作用域
})(variable)
AMD & CMD #
AMD (Asynchronous Module Definition)是 RequireJS 在推广过程中对模块定义的规范化产出.
CMD (Common Module Definition) 是 SeaJS 在推广过程中对模块定义的规范化产出。
对于依赖的模块,AMD 是提前执行,CMD 是延迟执行。不过 RequireJS 从 2.0 开始,也改成可以延迟执行(根据写法不同,处理方式不同)
CMD 推崇依赖就近,AMD 推崇依赖前置
// AMD
define(['./a', './b'], function(a, b) {
// 加载模块完毕可以使用
a.do()
b.do()
})
// CMD
define(function(require, exports, module) {
// 加载模块
// 可以把 require 写在函数体的任意地方实现延迟加载
var a = require('./a')
a.doSomething()
})
// AMD
define(['./a', './b'], function(a, b) {
// 加载模块完毕可以使用
a.do()
b.do()
})
// CMD
define(function(require, exports, module) {
// 加载模块
// 可以把 require 写在函数体的任意地方实现延迟加载
var a = require('./a')
a.doSomething()
})
ES6 Module #
- CommonJS 支持动态导入,也就是 require(${path}/xx.js),后者目前不支持,但是已有提案CommonJS 是同步导入,因为用于服务端,文件都在本地,同步导入即使卡住主线程影响也不大。而后者是异步导入,因为用于浏览器,需要下载文件,如果也采用同步导入会对渲染有很大影响。
- CommonJS 在导出时都是值拷贝,就算导出的值变了,导入的值也不会改变,所以如果想更新值,必须重新导入一次。但是 ES Module 采用实时绑定的方式,导入导出的值都指向同一个内存地址,所以导入值会跟随导出值变化
- ES Module 会编译成 require/exports来执行的
// 引入模块 API
import XXX from './a.js'
import { XXX } from './a.js'
// 导出模块 API
export function a() {}
export default function() {}
// 引入模块 API
import XXX from './a.js'
import { XXX } from './a.js'
// 导出模块 API
export function a() {}
export default function() {}
CommonJS #
CommonJS 是以在浏览器环境之外构建 javaScript 生态系统为目标而产生的写一套规范,主要是为了解决 javaScript 的作用域问题而定义的模块形式,可以使每个模块它自身的命名空间中执行,该规范的主要内容是,模块必须通过 module.exports 导出对外的变量或者接口,通过 require() 来导入其他模块的输出到当前模块的作用域中;目前在服务器和桌面环境中,node.js 遵循的是 CommonJS 的规范;CommonJS 对模块的加载时同步的;
ES6 模块与 CommonJS 模块的差异 #
- CommonJS 模块输出的是一个值的拷贝,ES6 模块输出的是值的引用。
- CommonJS 模块是运行时加载,ES6 模块是编译时输出接口。
- CommonJS 加载的是一个对象(即module.exports属性),该对象只有在脚本运行完才会生成。而 ES6 模块不是对象,它的对外接口只是一种静态定义,在代码静态解析阶段就会生成
定义模块 #
// module.js
let name = 'Vincent chen';
let sayName = function () {
console.log(name);
};
module.exports = { name, sayName }
// 或者
exports.sayName = sayName;
// module.js
let name = 'Vincent chen';
let sayName = function () {
console.log(name);
};
module.exports = { name, sayName }
// 或者
exports.sayName = sayName;
加载模块 #
// 通过 require 引入依赖
let module = require('./module.js');
module.sayName(); // Vincent chen
// 通过 require 引入依赖
let module = require('./module.js');
module.sayName(); // Vincent chen
module.export、exports的区别 #
- module.exports 方法还可以单独返回一个数据类型(String、Number、Object…),而 exports 只能返回一个 Object 对象
- 所有的 exports 对象最终都是通过 module.exports 传递执行,因此可以更确切地说,exports 是给 module.exports 添加属性和方法
exports.name = 'Vincent chen';
exports.age = 30;
console.log(module.exports); // result: { name: 'Vincent chen', age: 30 }
exports.name = 'Vincent chen';
exports.age = 30;
console.log(module.exports); // result: { name: 'Vincent chen', age: 30 }
- 同时用到module.export跟exports的时候
// case1
module.exports = { a: 1 }
exports.b = 2;
console.log(module.exports); // { a:1 }
// case2
module.exports.a =1;
exports.b = 2;
console.log(module.exports); // { a:1, b:2 }
// case1
module.exports = { a: 1 }
exports.b = 2;
console.log(module.exports); // { a:1 }
// case2
module.exports.a =1;
exports.b = 2;
console.log(module.exports); // { a:1, b:2 }
版权属于: vincent
转载时须注明出处及本声明
Tags: