解释
前端模块化是将一个复杂的系统分解出多个模块,每个模块职责单一、相互独立、高度解耦并可替换。一般前端模块化指的是Javascript的模块。最常见的是Nodejs的NPM包。
模块化开发的四点好处:
- 避免变量污染,命名冲突
- 提高代码复用率
- 提高了可维护性
- 方便依赖关系管理
模块化也是组件化的基石,是构成现在色彩斑斓的前端世界的前提条件。
常见的模块化规范
Javascript在早期的设计中就没有模块、包、类的概念,开发者需要模拟出类似的功能,来隔离、组织复杂的Javascript代码,我们称为模块化。有了模块化之后的代码,我们考虑更多的代码使用和维护成本问题,然后就有很多模块化的规范。常见的模块化规范有CommonJs、AMD、CMD、ES6 Module等规范。
CommonJs
CommonJs是服务端模块化规范,Nodejs采用了这个规范并把它发扬光大。
//example.js
var n = 1;
function sayHello( name ){
var name = name || "Tom";
return "Hello~"+name
}
function addFn(val){
var val = val.x+val.y;
return val
}
module.exports ={
n:n,
sayHello:sayHello,
addFn:addFn
}
//main.js
var example = require('./example.js');
var addNum = {
"x":10,
"y":5
}
console.log( example )//查看example输出的对外模块接口;
console.log( example.n )//1;
console.log( example.sayHello("Jack") )// "Hello~ Jack";
console.log( example.addFn(addNum) ) //15;
CommonJS 加载模块是同步的,所以只有加载完成才能执行后面的操作。像Nodejs主要用于服务器的编程,加载的模块文件一般都已经存在本地硬盘,所以加载起来比较快,不用考虑异步加载的方式,所以CommonJS规范比较适用。但如果是浏览器环境,要从服务器加载模块,这是就必须采用异步模式。所以就有了 AMD CMD 解决方案。
AMD(Asynchromous Module Definition) 异步模块定义
AMD 是客户端模块管理工具库RequireJS提出并且完善的一套模块化规范,AMD 是基于异步加载模块的方式。
特点 :异步加载,不阻塞页面的加载,能并行加载多个模块,但是不能按需加载,必须提前加载所需依赖
// 用define 定义模块
define({
method1: function() {},
method2: function() {},
});
// 定义模块时引用其他模块
define(['module1', 'module2'], function(m1, m2) {
...
});
// require 调用模块
require(['foo', 'bar'], function ( foo, bar ) {
foo.doSomething();
});
CMD(Common Module Definition)通用模块定义
CMD 是国内大牛玉伯提出来的,实现的库是SeaJs.
// test1.js
define(function(require,exports,module){
...
module.exports={
...
}
})
// test2.js
define(function(require,exports,module){
var cmd = require('./test1')
// cmd.xxx 依赖就近书写
// 通过 exports 对外提供接口
exports.doSomething = ...
// 或者通过 module.exports 提供整个接口
module.exports = ...
})
- 对于依赖的模块,AMD 是提前执行,CMD 是延迟执行。
- CMD 推崇依赖就近,AMD 推崇依赖前置。
define(function(require, exports, module) {
var a = require('./a')
a.doSomething()
// 此处略去 100 行
var b = require('./b') // 依赖可以就近书写
b.doSomething()
// ...
})
// AMD 默认推荐的是
define(['./a', './b'], function(a, b) { // 依赖必须一开始就写好
a.doSomething()
// 此处略去 100 行
b.doSomething()
...
})
ES6 Module
在 ES6 之前,社区制定了一些模块加载方案,最主要的有 CommonJS 和 AMD 两种。前者用于服务器,后者用于浏览器。ES6 在语言标准的层面上,实现了模块功能,而且实现得相当简单,完全可以取代 CommonJS 和 AMD 规范,成为浏览器和服务器通用的模块解决方案。
ES6 的模块自动采用严格模式,不管你有没有在模块头部加上"use strict"
;并使用export、import 命令实现导出引用模块。
// profile.js
var firstName = 'Michael';
var lastName = 'Jackson';
var year = 1958;
export { firstName, lastName, year };
// main.js
import { firstName, lastName, year } from './profile.js';
function setName(element) {
element.textContent = firstName + ' ' + lastName;
}
//export default 命令
// export-default.js
export default function () {
console.log('foo');
}
// import-default.js
import customName from './export-default';
customName(); // 'foo'
ES6 Module 与 CommonJS 的区别
- CommonJS 模块输出的是一个值的拷贝,ES6 模块输出的是值的引用。
- CommonJS 模块是运行时加载,ES6 模块是编译时输出接口。
区分模块与组件
前端模块侧重的功能的封装,主要是针对Javascript代码,隔离、组织复制的javascript代码,将它封装成一个个具有特定功能的的模块。
模块可以通过传递参数的不同修改这个功能的的相关配置,每个模块都是一个单独的作用域,根据需要调用。
一个模块的实现可以依赖其它模块。
前端组件更多关注的UI部分,页面的每个部件,比如头部,底部、内容区,弹出框都可以成为一个组件,每个组件有独立的HTML、CSS、JS代码。
可以根据需要把它放在页面的任意部位,也可以和其他组件一起形成新的组件。一个页面是各个组件的结合,可以根据需要进行组装。
扩展:站在业务的角度架构的视角模块组件又可以这么分。
模块和组件都是系统的组成部分。
从逻辑角度拆分系统后,得到的单元就是“模块”。
从物理角度来拆分系统后,得到的单元就是“组件”。
划分模块的主要目的是职责分离,划分组件的主要目的是单元复用。
假设我们要做一个学生管理系统,这个系统从逻辑的角度拆分,可以分为“登录注册模块”“个人成绩模块”;从物理的角度来拆分,可以拆分为Nginx、Web服务器、MySql。
参考:
浅谈前端模块化
前端模块与组件的区别
30分钟学会前端模块化开发
前端模块化、组件化的理解
知乎玉伯回复CMD和AMD的区别
[阮一峰ES6 Module 语法]()
[ES6 Module与CommonJs的差异化]()
从零开始学架构(李运华)
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。