模块化开发
一、组合模式
组合模式又叫部分整体模式。把一组相似的对象当做单一的对象处理。组合模式依据树形结构,用来表示部分和整体。
创建一个包含自己对象组的基(父)类,该类提供了修改相同对象组的方式。其他类继承自该基类,基类不实例化任何的对象。
/*
组合模式的定义: 定义一个基类,该基类要具有组合的所有属性和方法,他不产生实例对象,被其他类继承
*/
// 定义基类
function Base() {
// 属性
this.dom = null;
this.children = [];
}
// 设置基类的方法
// 添加子元素
Base.prototype.add = function(child) {
this.children.push(child);
return this;
}
// 渲染元素
Base.prototype.render = function() {
// 上树
// 备份this
var me = this;
this.children.forEach(function(child) {
me.dom.appendChild(child.dom);
})
}
// 创建最大的容器----树根
function Container() {
// 寄生式组合继承
Base.call(this);
// 创建一个ol
this.dom = document.createElement('ol');
}
// 继承方法
Container.prototype = Object.create(Base.prototype);
// 创建li容器
function Item() {
Base.call(this);
// 创建一个li
this.dom = document.createElement('li');
}
// 继承方法
Item.prototype = Object.create(Base.prototype);
// 创建文本节点----最小的节点,不需要包含子元素
function Leaf(text) {
// createTextNode 创建文本节点, text文字内容
this.dom = document.createTextNode(text);
}
// 创建树叶---文本节点
var leaf1 = new Leaf('31省新增本土确诊42例:河北40例');
var leaf2 = new Leaf('特朗普夫人发文谴责国会*');
var leaf3 = new Leaf('河北固安全县居民居家隔离7天');
var leaf4 = new Leaf('蒙古发生6.8级地震');
var leaf5 = new Leaf('北京新增1例本土确诊 系5岁男童');
// 创建树枝---li
var li1 = new Item();
var li2 = new Item();
var li3 = new Item();
var li4 = new Item();
var li5 = new Item();
// 创建树根---ol
var ol = new Container();
// 将树叶添加到树枝上
li1.add(leaf1).render();
li2.add(leaf2).render();
li3.add(leaf3).render();
li4.add(leaf4).render();
li5.add(leaf5).render();
// 添加子元素
ol.add(li1).add(li2).add(li3).add(li4).add(li5).render();
// 父元素上树
document.body.appendChild(ol.dom);
二、观察者模式
特别重要
观察者模式又叫: 消息管道、订阅-发布、消息机制、自定义事件
当对象存在一对多的关系,则使用观察者模式。当一个对象被修改的时候,需要通知依赖他的对象,这种模式称之为观察者模式。
在js中的应用有两个方面: 一对多的修改, 跨模块传输消息。
DOM0级观察者:
var Observer = (function() {
// 设置一个存储绑定处理程序的对象,存储数据
var obj = {
}
return {
// 绑定事件
on: function(type, fn) {
obj[type] = fn;
},
// 触发事件
trigger: function(type) {
obj[type]();
},
// 辅助方法---用于查看对象obj
log: function() {
console.log(obj);
}
}
})();
DOM2级观察者:
/*
使用DOM0 事件实现观察者
1、绑定事件
2、触发事件
DOM2级绑定多个事件, 移除指定的事件
*/
var OBserver = (function() {
// 设置一个存储绑定处理程序的对象,存储数据
var obj = {
}
return {
// 绑定事件
on: function(type, fn) {
// 判断条件
if (obj[type]) {
// 不是第一次添加
obj[type].push(fn);
} else {
// 第一次添加
obj[type] = [fn];
}
},
// 触发事件
trigger: function(type) {
// 由于事件是数组的形式,所以依次调用触发
obj[type].forEach(function(fn) {
fn();
})
},
// 移除事件,移除指定type全部处理程序和移除type指定的处理程序,移除所有的程序
/*
移除指定type: off(type)
移除type中指定的处理程序: off(type, fn)
清空所有: off()
*/
off: function(type, fn) {
if (arguments.length == 0) {
// 清空所有
obj = {};
} else if (arguments.length == 1) {
obj[type] = [];
} else if (arguments.length == 2) {
for (var i = 0; i < obj[type].length; i++) {
if (obj[type][i] == fn) {
// 移除
obj[type].splice(i, 1);
}
}
}
},
// 一次性事件
one: function(type, fn) {
// 绑定上事件,执行的时候,立即移除该事件
// 跟bind类似,bind方法改变this的指向,绑定一个函数,但是在返回的时候,给的函数和我们传入的不是一个函数
function _demo() {
fn();
// 执行完毕移除对应的函数
OBserver.off(type);
}
// 将demo进行绑定
OBserver.on(type, _demo);
},
// 辅助方法---用于查看对象obj
log: function() {
console.log(obj);
}
}
})();
三、模块化
早期js设计之初,为了解决表单验证的问题。ES6引入了块作用域,查找变量按照作用域链的方式进行查找,声明的时候也是同样的道理。没有类、没有包、更没有模块,带来代码的复用、依赖、冲突,代码的组织混乱。随着前端功能的膨胀,模块化被提出来了。
前端模块化:
- 浏览器端
- AMD: 异步模块规范 ---- RequireJS
- CMD: 普通模块规范 ---- SeaJS
- node端(服务器端)— CommonJS–同步模块规范
- 浏览器和服务器端兼容:UMD规范–通用模块规范
- ES6原生模块
3.1 模块概述
js没有实现包、类、模块这些概念,开发者模拟类似的功能,来隔离、组织复杂的js代码,称之为模块化。
模块就是一个实现特定功能的文件,有了模块我们就可以更方便的使用别人的代码,要什么功能就引入什么模块。
模块化的好处:
- 避免变量的污染,命名冲突
- 提高了代码的可维护性
- 提高代码的复用
- 方便依赖关系的管理
3.2 模块的发展历程
3.2.1 函数
// 功能1
function fn1() {
}
// 功能2
function fn2() {
}
污染全局变量,不能保证函数名不被覆盖,成员之间的依赖关系没有办法解决
3.2.2 对象
var Module = {
// 属性
property1: value1,
property2: value2,
// 方法
method1: function() {
},
method2: function() {
}
}
外部可以肆意的更改你的对象,安全问题
3.2.3 IIFE
隐藏细节,保护变量,只能通过制定方式进行读取和使用
var Module = (function() {
var obj = {
// 属性
property1: value1,
property2: value2,
// 方法
method1: function() {
},
method2: function() {
}
}
return {
method1: obj.method1,
method2: obj.method2
}
})()
封装过程复杂,使用了闭包增加了开销。
<script src="js/Bg.js"></script>
<script src="js/Bird.js"></script>
<script src="js/Game.js"></script>
<script src="js/Land.js"></script>
<script src="js/Pipe.js"></script>
但是,在工作中经常存在js文件之间的依赖关系,后面的文件需要依赖前面的文件,在整个的引入过程中,这些文件是不可以随意更改顺序的。
3.3 模块化规范
共同的特点: 一个js文件就是一个模块
- 浏览器端
- AMD: 异步模块规范 ---- RequireJS
- CMD: 普通模块规范 ---- SeaJS
- node端(服务器端)— CommonJS–同步模块规范
- 浏览器和服务器端兼容:UMD规范–通用模块规范
- ES6原生模块
3.3.1服务器端
CommonJS让js程序员可以使用js来执行python、java等服务器端的编程,nodejs采用的该规范。
加载是同步的
服务器端: 同步加载
3.3.2 浏览器端
加载的文件为远程加载,必须使用异步加载
AMD和CMD本质都是异步加载
AMD: Asynchronous Module Definition —异步模块定义
CMD: Common Module Definition — 通用模块定义
AMD和CMD最大的区别:
AMD提前加载(依赖前置),CMD依赖就近(懒加载)
3.3.3 UMD
UMD: Universal Module Definition 通用模块定义
UMD是AMD和CommonJS的产物,浏览器端和服务器端的兼容。
UMD是存在判断过程的,如果你是node定义的模块使用CommonJS规范,如果不是node定义的,是客户端,使用AMD规范。
四、模块化的学习
1、定义模块
2、引入模块
3、seajs和requirejs的插件和配置