模块化
- 解决的问题:加载顺序、变量全局污染
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)AMD#
Asynchronous 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), }})CMD#
Common 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模块化#
exportimport... from- 加上
defaultimport时不能使用解构赋值了
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])}ES6与CommonJs区别#
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。
模块化的优势有以下几点:
- 防止命名冲突
- 代码复用
- 高维护性