文章目录
- 一、模块化
- 1、模块化的最初
- 2、模块化解决什么问题
- 3、IIFE立即执行函数
- 4、插件化
- 5、JS引擎遇到script标签做了什么
- 6、NodeJS带来的模块化体验
- CommonJS特点
- require
- 使用
- 7、客户端的CommonJS(AMD)
- 8、通用模块定义Common Module Definition(CMD)
- 9、ES官方推出:ES6模块化
- 10、CommonJS跟ES6模块化的区别
一、模块化
1、模块化的最初
- IE6之前,是没有JS引擎的
- JS代码都是写在script标签中
- 随着JavaScript的发展,慢慢的就将JS通过外部脚本引入
2、模块化解决什么问题
- 将JavaScript架构跟逻辑分离开
- 抽离公共JS模块,然后引入
- 不能光通过以页面为基础,来分程序块,分JS文件
模块化解决的问题:
- 加载顺序
- 污染全局 -> 数据类型的变量
3、IIFE立即执行函数
解决变量污染全局跟依赖的问题,不会解决加载顺序的问题
- 立即执行函数 -> 闭包 -> 模块的注入
约定俗成在立即执行函数前面加上分号
- 函数有自己的作用域和执行期上下文,所以我们可以通过立即执行函数创建模块的独立作用域
一个模块一般都是将对象的方式抛出去,他才是可拓展的
var moduleA = (function() {
var a = [1, 2, 3];
return { // 这里形成了闭包,函数被销毁,但是该作用域还存在
a: a
}
})();
// 模块注入:模块独立,并且可以相互依赖
var moduleB = (function(moduleA) {
var b = moduleA.a.concat([4, 5, 6]);
return {
b: b
}
})(moduleA);
// 使用
(function (moduleA, moduleB) {
console.log(moduleA.a);
console.log(moduleB.b);
})(moduleA, moduleB);4、插件化
插件化是由开发者通过一遍又一遍的试验来定义的:立即执行函数实现插件化
- 函数声明不是表达式,只要不是表达式就不能加执行符号
() - 只要是表达式就可以在后面加执行符号
(),被括起来就是表达式
将架构和逻辑分离开来,是最简单的模块化方式
5、JS引擎遇到script标签做了什么
会阻塞,遇到第一个script时,后面的script不会执行,要等待第一个script加载完才执行
- 多个script标签会产生变量覆盖问题,变量重名问题,会污染全局
6、NodeJS带来的模块化体验
NodeJS诞生带来了前所未有的模块化体验:require导入 module.exports 导出
CommonJS特点
- 是一种模块化规范
- 用的require引用,只要一引用就会创建一个模块实例
- 有缓存机制,在Node上运行,依赖webpack解析,是同步方法
- 写服务端用CommonJS比较多
require
- require并不是全局变量,只要引进来之后就会被解析成一个立即执行函数
(function(exports, require, module, __filename, __dirname) {
})();使用
/** module_a.js */
var a = (function() {
return [1, 2, 3].reverse();
})();
module.exports = { // 导出
a: a
}
/** module_b.js */
var moduleA = require('./module_a'); // 引入模块
var b = (function() {
return moduleA.a.concat([4, 5, 6]);
})();
module.exports = { // 导出
b: b
}
/** module_c.js */
var moduleB = require('./module_b');
var c = (function() {
return moduleB.b.join('-');
})();
module.exports = {
c: c
}
/** index.js */
var moduleA = require('./module_a');
var moduleB = require('./module_b');
var moduleC = require('./module_c');
console.log(moduleA.a);
console.log(moduleB.b);
console.log(moduleC.c);7、客户端的CommonJS(AMD)
通过requireJS实现AMD
- AMD:
Asynchronous Moudle Definition异步模块定义 - define定义模块 require使用模块
阿里为模块化做了贡献:CMD,Common Module Definition 通用模块定义
- 特点
- 实现了异步加载模块
- require的时候,所有模块加载完毕,回调函数才会执行 -> 前置依赖
- 规范了模块的输入输出
- 定义模块
define(moduleName, ['module'], factory);- 引入模块
require(['module'], callback);- 使用
<script src="./require.js"></script>
<script src="./index.js"></script>// ---------- module_a.js ----------
define('moduleA', function() {
var a = [1, 2, 3, 4, 5];
return {
a: a.reverse();
}
})
// ---------- module_b.js ----------
define('moduleB', ['moduleA'], function(moduleA) {
var b = [6, 7, 8, 9, 10];
return {
b: moduleA.a.concat(b);
}
})
// ---------- module_c.js ----------
define('moduleC', ['moduleB'], function(moduleB) {
return {
c: moduleB.b.join('-')
}
})
// ---------- index.js ----------
// 需要配置路径
require.config({
paths: {
moduleA: 'js/module_a',
moduleB: 'js/module_b',
moduleC: 'js/module_c',
}
})
require(['moduleA', 'moduleB', 'moduleC'], function(moduleA, moduleB, moduleC) {
console.log(moduleA.a);
console.log(moduleB.b);
console.log(moduleC.c);
})8、通用模块定义Common Module Definition(CMD)
- 特点:
- CMD 通过 require 加载, defined 定义, exports 导出, module 操作模块
- 使用模块是需要配置模块URL
- 依赖加载完毕后执行factory
- 依赖就近 按需加载
- 这是和CommonJS AMD本质的不同
- AMD:依赖前置,全部都加载完成,才执行回调
- CMD:需要的时候在加载,依赖就近,按需加载
// 定义模块
define(function(require, exports, module) {});
// 使用模块
seajs.use([module路径], function(moduleA, moduleB, moduleC) {})- 使用
<!-- 引入sea.js -->
<script src="./sea.js"></script>
<script src="./index.js"></script>// ---------- module_a.js ----------
define(function(require, exports, module) {
var a = [1, 2, 3, 4, 5];
return {
a: a.reverse();
}
})
// ---------- module_b.js ----------
define(function(require, exports, module) {
var moduleA = require('module_a'),
b = [6, 7, 8, 9, 10];
return {
b: moduleA.a.concat(b);
}
})
// ---------- module_c.js ----------
define(function(require, exports, module) {
var moduleB = require('module_b');
return {
c: moduleB.b.join('-')
}
})
// ---------- index.js ----------
seajs.use(['module_a.js', 'module_b.js', 'module_c.js'], function(moduleA, moduleB, moduleC) {
console.log(moduleA.a);
console.log(moduleB.b);
console.log(moduleC.c);
})9、ES官方推出:ES6模块化
// 导入模块
import module from '模块路径';
//导出模块
export module;- 使用
// ---------- module_a.js ----------
export default {
a: [1, 2, 3, 4].reverse()
};
// ---------- module_b.js ----------
// b.js 里引入模块
import moduleA from './module_a';
export default {
b: moduleA.a.concat([6, 7, 8, 9])
}
// ---------- module_c.js ----------
import moduleB from './module_b';
export default {
c: moduleB.b.join('-')
}
// ---------- index.js ----------
import moduleA from './module_a',
import moduleB from './module_b',
import moduleC from './module_c';
console.log(moduleA.a);
console.log(moduleB.b);
console.log(moduleC.c);10、CommonJS跟ES6模块化的区别
- CommonJS模块输出的是一个值的拷贝,ES6模块化输出的是值的引用
- CommonJS模块是在运行时加载,ES6模块是在编译时加载
// ---------- export.js ----------
exports.a = 0;
setTimeout(() => {
console.log('exportJS', ++exports.a); // 1
}, 300)
// ---------- common.js ----------
const {
a
} = require('./export');
setTimeout(() => {
console.log('commonJS', a); // 0
}, 500)
// ---------- es6.js ----------
import {
a
} from './export';
setTimeout(() => {
console.log('es6', a); // 1
}, 500)YUI
















