1. 什么是模块化开发?
模块化开发有点像分工合作, 比方说一个手机, 它是由一系列的功能模块组合在一起的, 比如摄像头, 屏幕, cpu, 操作系统, 而每个功能模块可能是由不同公司生产的, 比如从 A 公司买的处理器, B 公司做的摄像头, C 公司加工的屏幕.
网页也是这样, 当代码量越来越大, 功能越来越复杂的时候, 我们就很难一个代码中完成所有的工作, 所以需要将不同的功能模块封装外包出去, 或者直接使用别人写好的模块.
而像这种通过特定的方式实现所需模块的划分, 管理和加载的机制就叫做模块化开发.
所以模块化开发的最大的好处就是协同和代码复用. 如果说这两个好处对你而言没有太大的感受, 那么下面这些问题可能就是你的亲身经历. 1. 大量的文件引入; 2. 代码写的多了, 经常会有命名冲突; 3. 类似的功能写了不下 800 遍; 4. 经常搞乱文件依赖
2. 如何使用模块化开发
1. 全局函数
在最早的时候, 我们将一些重复使用的代码封装成函数, 所以一个函数就是一个模块. 比如最简单的一个加法运算函数.
- function add(a,b) {
- return a+b;
- }
这是一种约定形式的模块, 存在命名冲突, 可维护性不高等问题. 仅仅从代码角度而言, 没有任何模块的概念.
2. 对象
为了解决全局函数的这些问题, 可以把函数封装成对象的属性, 把这个对象当成一个模块.
- var calculator = {
- add:function(a,b) {
- return a+b;
- }
- }
从代码层面来说, 已经有个模块的感觉. 但是也有缺点, 还是会污染全局 (但因为一个模块只会暴露一个变量, 所以是可以接受的), 另一个缺点就是这样的写法会暴露所有模块成员, 没有私有空间, 内部状态可以被外部改写.
比如我写了一个管理员的模块, 模块内部需要对密码进行加密, 那我这个加密算法肯定不希望被别人知道.
3. 自执行函数
js 中没有块级作用域, 它的作用域是基于函数的, 所以我们可以把模块封装在一个自执行函数里面, 如果需要暴露就直接 return 出去, 没有 return 的均为私有方法.
- var calculator = (function() {
- // 私有函数
- function parse(str) {
- return parseFloat(str);
- }
- function add(a,b) {
- return parse(a)+parse(b);
- }
- // 暴露函数
- return {
- add:add
- }
- })
相比与之前的方法, 自执行函数有了很大的进步, 但是当我们想要维护这个模块的时候却不是那么方便. 比如我想添加一个计算变量相乘的方法, 就只能去修改原来的模块.
4. 自执行函数进阶版
- (function(calculator) {
- // 私有函数
- function parse(str) {
- return parseFloat(str);
- }
- calculator.add = function(a,b) {
- return parse(a)+parse(b);
- }
- // 重新挂载
- window.calculator = calculator;
- })(window.calculator || {})
现在我们需要新增一个方法就很很简单, 而且不用修改以前的模块.
- (function(calculator) {
- // 如果 calculator 存在就扩展, 如果不存在就创建
- })(window.calculator || {})
这种写法已经比较完善了, 但是如果有全局变量, 而模块内又想用怎么办? 比如说 jquery. 当然直接使用也是可以的, 但是一个模块最好是一个高内聚低耦合的一个状态. 也就是说, 模块内部高度关联, 模块与外部函数尽量避免直接交互.
所以, 我们还有一个终极版本来解决全局依赖, 我们把全局变量也通过参数传递进去.
- (function(calculator,$) {
- // 私有函数
- function parse(str) {
- return parseFloat(str);
- }
- calculator.add = function(a,b) {
- return parse(a)+parse(b);
- }
- // 重新挂载
- window.calculator = calculator;
- })(window.calculator || {}, jQuery)
以上是传统的 JS 模块化的方法, 但其实 ES6 已经提供了模块的方法.
简单介绍一下, ES6 模块功能主要由两个命令构成: export 和 import.export 命令用于规定模块的对外接口, import 命令用于输入其他模块提供的功能.
- function add(a,b) {
- return a + b;
- }
- export {
- add
- }
- import {add} from './calculator.js';
大家有兴趣可以看一下阮一峰的免费电子书, 里面有详细的介绍 ( http://es6.ruanyifeng.com/#docs/module )
ES6 在语言标准的层面上, 实现了模块功能, 而且实现得相当简单. 如果代码支持 ES6 那么完全可以用 ES6 的模块语法就行,
但是如果代码不支持, 那么我们可能就得寻求一些第三方软件的支持.
来源: http://www.jianshu.com/p/ea8ab42356b8