模块化
- 解决的问题:加载顺序、变量全局污染
#
ES5// 立即执行函数 解决全局污染;(function(){ // 可以使模块拥有独立的作用域 执行上下文})();
#
Demo//ES5 可以解决全局污染 还是无法解决加载顺序
// index.html <script src="./a.js"></script> <script src="./b.js"></script> <script src="./index.js"></script>
// a.jslet moduleA = (function () { let a = [1, 2, 3, 4, 5].reverse() return { a: a }})()
// b.jslet moduleB = (function (moduleA) { let b = moduleA.a.concat([6, 7, 8]) return { b: b }})(moduleA)
// index.js;(function (moduleA, moduleB) { console.log(moduleA.a) console.log(moduleB.b)})(moduleA, moduleB)
CommonJs
#
CommonJs
是 Node 独有的规范,浏览器中使用就需要用到Browserify
解析了。CommonJs
引用 就会创建模块实例 实例化JS
文件- 同步加载文件
- 缓存机制(缓存模块 判断前后两次异同
- 服务端 Node
- 导入:
require
- 导出:
module.exports = {}
#
Demo// index.html <script src="./index.js"></script>
// a.jslet a = (function () { return [1, 2, 3, 4, 5].reverse()})()module.exports = {a}//exports.a?
// b.jslet moduleA = require('./a.js')let b = (function () { return moduleA.a.concat([6, 7, 8])})()module.exports = {b}
// index.jslet moduleA = require('./a'), moduleB = require('./b')console.log(moduleA.a)console.log(moduleB.b)
#
AMDAsynchronous Module Definition
异步模块定义- AMD 是由
RequireJS
提出的 执行时也需要requireJs
define(moduleName,[module],factory)// 模块名 依赖模块 工厂函数require([module],callback)
#
Demo// index.html <script src="./require.js"></script> <script src="./index.js"></script>
// index.js// 前置依赖(等模块全部加载完才执行回调函数) 异步执行(async) 不考虑模块加载顺序require.config({ path: { moduleA: './a', moduleB: './b', },})
require(['moduleA', 'moduleB'], function (moduleA, moduleB) { console.log(moduleA.a) console.log(moduleB.b)})
// a.jsdefine('moduleA', function () { let a = [1, 2, 3, 4, 5] return { a: a.reverse(), }})
// b.jsdefine('moduleB', ['moduleA'], function (moduleA) { let b = [6, 7, 8] return { b: moduleA.a.concat(b), }})
#
CMDCommon Module Definition
通用模块定义
define(function (require, exports, module){})seajs.use([module], function(moduleA,...){})
#
Demo// index.html <script src="./sea.js"></script> <script src="./index.js"></script>
// index.js// 依赖就近 按需加载(需要的时候才去加载。 不像依赖前置)seajs.use(['a.js', 'b.js'], function(moduleA,moduleB,moduleC){ console.log(moduleA.a) console.log(moduleB.b)})
// a.jsdefine(function (require, exports, module) { let a = [1, 2, 3, 4, 5] return { a: a.reverse(), }})
// b.jsdefine(function (require, exports, module) { let moduleA = require('a'), b = [6, 7, 8] return { b: moduleA.a.concat(b), }})
//require 加载 define 定义//exports 导出 module 操作模块
#
ES6模块化export
import... from
- 加上
default
import
时不能使用解构赋值了
#
Demo// index.html <script src="./index.js"></script>
// index.jsimport moduleA from './a'import moduleB from './b'console.log(moduleA.a)console.log(moduleB.b)
// a.jsexport default { a:[1,2,3,4,5].reverse()}
// b.jsimport moduleA from './a'export default { b : moduleA.a.concat([6,7,8])}
CommonJs
区别#
ES6与CommonJS
模块输出的是一个值的拷贝,ES6
模块输出的是值的引用CommonJS
模块是运行时加载,ES6
模块是编译时加载CommonJS
是单个值导出,ES6 Module
可以导出多CommonJS
是动态语法可以写在判断里,ES6 Module
静态语法只能写在顶层CommonJS
的this
是当前模块,ES6 Module
的this
是undefined
- 前者支持动态导入,也就是
require(${path}/xx.js)
,后者目前不支持,但是已有提案 - 前者是同步导入,因为用于服务端,文件都在本地,同步导入即使卡住主线程影响也不大。而后者是异步导入,因为用于浏览器,需要下载文件,如果也采用同步导入会对渲染有很大影响
- 前者在导出时都是值拷贝,就算导出的值变了,导入的值也不会改变,所以如果想更新值,必须重新导入一次。但是后者采用实时绑定的方式,导入导出的值都指向同一个内存地址,所以导入值会跟随导出值变化
- 后者会编译成
require/exports
来执行的
//export.js 1exports.a = 0setTimeout(()=>{ console.log('来自export', ++exports.a)},300)
//commonjs 0const {a} = require('./export.js')setTimeout(()=>{ console.log('来自commonjs', a)},500)
//ES6 1import {a} from './export'setTimeout(()=>{ console.log('来自ES6', a)},500)
import
和export
的区别?#
- Module 主要由两个命令组成,import和export,export命令用于规定模块的对外接口,import命令用于输入其他模块提供的功能。
- 导出模块是export,导入模块是import。
模块化的优势有以下几点:
- 防止命名冲突
- 代码复用
- 高维护性