什么是模块化
定义:
模块化就是把系统分离成独立功能的方法,这样我们需要什么功能,就加载什么功能
- 每个模块都是独立的,良好设计的模块会尽量与外部的代码撇清关系,以便于独立对其进行改进和维护
- 可以重复利用,而不用经常复制自己之前写过的代码
模块化的好处
优点:
-
可维护性
- 灵活架构,焦点分离
- 方便模块间组合、分解
- 方便单个模块功能调试、升级
- 多人协作互不干扰
可测试性
拓展:
缺点:
性能损耗
1、系统分层,调用链会很长
2、模块间发送消息会很耗性能
模块化主要解决两个问题,"命名冲突"、"文件依赖"
命名冲突
// a.js
var a = 1;
// b.js
var a = 2;
文件依赖
// b.js依赖a.js,标签的书写顺序必须是:
<script src='a.js' type='text/javascript'></script>
<script src='b.js' type='text/javascript'></script>
解决冲突、依赖(按需加载)
使用命名空间
这样的写法会暴露所有模块内的成员,内部状态可以被外部改写
let module = {
name: 'likang xie',
sayName() {
console.log(this.name);
}
}
立即执行函数+闭包
函数内部有自己独立的作用域,外部只能访问自己暴露的成员而不能读取内部的私有成员
let module = (function () {
let privateName = 'private'; // 私有变量
let privateFn = function () {}; // 私有函数
// 对外暴露的成员
return {
name: 'likang xie', // 公有属性
sayName() { // 公有方法
console.log(this.name);
}
}
})();
// 外部调用
module.sayName(); // likang xie
使用立即执行函数+类
同上
const People = (function () {
let privateName = 'private'; // 私有变量
let fn = function () {}; // 私有方法
return class People {
constructor () {
this.name = 'likang xie'; // 公有变量
}
// 公有方法
sayName() {
console.log(this.name);
}
}
})()
CommonJs(用于Node环境)
根据CommonJs规范,每个文件就是一个模块,有自己的作用域。在一个文件里面定义的变量、函数、类,都是私有的,对其他文件不可见,CommonJS规范加载模块是同步的,也就是说,加载完成才可以执行后面的操作,Node.js主要用于服务器编程,模块一般都是存在本地硬盘中,加载比较快,所以Node.js采用CommonJS规范。
定义模块
// module.js
let name = 'liakng xie';
let sayName = function () {
console.log(name);
};
module.exports = { name, sayName }
// 或者
exports.sayName = sayName;
加载模块
// 通过 require 引入依赖
let module = require('./module.js');
module.sayName(); // likang xie
module.export跟exports的区别
- module.exports 方法还可以单独返回一个数据类型(String、Number、Object...),而 exports 只能返回一个 Object 对象
- 所有的 exports 对象最终都是通过 module.exports 传递执行,因此可以更确切地说,exports 是给 module.exports 添加属性和方法
exports.name = 'likang xie';
exports.age = 21;
console.log(module.exports); // 运行结果:{ name: 'likang xie', age: 21 }
3.同时用到module.export跟exports的时候
// 情况1
module.exports = { a: 1 }
exports.b = 2;
// { a:1 }
console.log(module.exports);
// 情况2
module.exports.a =1;
exports.b = 2;
// { a:1, b:2 }
console.log(module.exports);
AMD(用于浏览器环境)
AMD是"Asynchronous Module Definition"的简写,也就是异步模块定义。它采用异步方式加载模块。通过define方法去定义模块,require方法去加载模块。
定义模块
define(['module'], function() {
let name = 'likang xie';
function sayName() {
console.log(name);
}
return { sayName }
})
使用模块
// 通过 require 引入依赖
require(['module'], function(mod) {
mod.sayName(); // likang xie
})
RequireJs
什么是RequireJs
RequireJS 是一个JavaScript模块加载器。
在ES6出现之前,JS不像其他语言同样拥有“模块”这一概念,于是为了支持JS模块化,出现了各种各样的语言工具,如webpack,如ReuqireJS。
为什么使用RequireJS
· 不会阻塞页面:RequireJS,会在相关的js加载后执行回调函数,这个过程是异步的,所以它不会阻塞页面。
· 按需加载:平时我们写html文件的时候,在底部可能会引用一堆js文件。在页面加载的时候,这些js也会全部加载。使用require.js就能避免此问题。举个例子,比如说我写了一个点击事件,放到了一个js文件里,并在html引用,在不使用require.js的情况下,页面加载它跟着加载,使用后则是什么时候触发点击事件,什么时候才会加载js。
CMD(用于浏览器环境)
CMD与AMD用法很相似
定义模块、使用模块
define(function(require, exports, module) {
// 通过 require 引入依赖
var otherModule = require('./otherModule');
// 通过 exports 对外提供接口
exports.myModule = function () {};
// 或者通过 module.exports 提供整个接口
module.exports = function () {};
})
seaJS
什么是 seaJS
和requireJS相似的,seaJS 也是用JavaScript编写的JS框架,主要功能是可以按不同的先后依赖关系对 JavaScript 等文件的进行加载工作,可简单理解为JS文件的加载器,它非常适合在浏览器中使用,它可以确保所依赖的JS文件加载完成之后再加载当前的JS文件,这在大量使用JS文件的项目中可确保各个JS文件的先后加载顺序,确保避免了以前因某些原因某个文件加载慢而导致其它加载快的文件需要依赖其某些功能而出现某函数或某变量找不到的问题,这点非常有用,也是 seaJS (遵守CMD) 的主要价值所在吧;但和 requireJS (遵守AMD规范)有所区别。
快速简要知识点:
seajs.config({...}); //用来对 Sea.js 进行配置。
seajs.use(['a','b'],function(a,b){...}); //用来在页面中加载一个或多个模块。
define(function(require, exports, module){...}); //用来定义模块。Sea.js 推崇一个模块一个文件,遵循统一的写法
require(function(require){var a = require("xModule"); ... }); //require 用来获取指定模块的接口。
-
require.async, //用来在模块内部异步加载一个或多个模块。 例如:
define(function(require){ require.async(['aModule','bModule'],function(a,b){ // 异步加载多个模块,在加载完成时,执行回调 a.func(); b.func(); }) }); -
exports, //用来在模块内部对外提供接口。 例如:
define(function(require, exports){ exports.varName01 = 'varValue'; // 对外提供 varName01 属性 exports.funName01 = function(p1,p2){ // 对外提供 funName01 方法 .... } }); -
module.exports, 与 exports 类似,用来在模块内部对外提供接口。例如:
define(function(require, exports, module) { module.exports = { // 对外提供接口 name: 'a', doSomething: function() {...}; }; });ES6模块(用于浏览器环境)
模块功能主要由两个命令构成:export和import。export命令用于规定模块的对外接口,import命令用于输入其他模块提供的功能。
定义模块、输出变量
a.js
export default { name: 'likang xie' }b.js
// 输出多个变量 export let name = 'likang xie'; export let sayName = () => console.log(name);使用模块
import people from 'a.js'; console.log(people); // { name: 'likang xie' }// 将所有获取到的变量存到people里 import * as people from 'b.js'; console.log(people); // 一个module对象 { name: 'likang xie', sayName: .... } // 或者 import { name, sayName } from 'b.js';