设计模式让我们按某种方式实现一些功能,增强了代码的可读性。
设计模式需要有面向对象的思想,有Java
基础的话理解就更透彻了;看个人喜好,对你有帮助去用,而不是为了用而用。
函数定义
几种函数声明方法:
-
普通
function user(){...};
-
挂载到原型链
var user = function(){...}; // 声明式,添加方法到原型链上 user.prototype.addName = function(){...}; // 重写式,重写原型链 user.prototype = { addName(){...} };
-
修改
Function
对象,扩展一个添加函数addMethod
这种方式还没用过Function.prototype.addMethod = function(name,fn){ this.prototype[name] = fn; } var user = function(){...}; user.addMethod("addName",function(){...});
设计模式三个特性:
-
接口:提供统一方法
-
封装:信息私有
function User(){ let tip = "welcome"; // 内部私有属性 this.name = "admin"; this.age = 34; this.setAge=function(){}; this.getAge=function(){}; } let user = new User(); // user 是访问不到tip 的。
-
继承:属性、方法重用
// 定义测试父类 function Parent(){ this.name = "parent"; } Parent.prototype.getName = function(){ return this.name; }
类式继承
function Child(){} Child.prototype = new Parent();
访问到父类中的公共属性和方法。
构造函数继承function Child(){ Parent.call(this,"child"); } // 修改一下父类的构造方法 function Parent(name){ this.name = name; }
改变子类实例化父类时共有属性的值。
组合继承
工厂模式
将众多小模块对象封装到一个大对象中实现一个功能。
简单工厂模式
返回差异部分的不同实例或者返回一个新的对象。
用户登陆获取各自的权限:
function User(name){
let user = new Object();
user.show = function(){
console.log("欢迎登陆!");
}
if(name == "admin"){
// 管理员权限
}
if(name=="test"){
// 测试人员权限
}
return user;
}
工厂方法模式
通过不同类型创建并返回实例。
不同用户行使各自权利:
function User(name){
if(this instanceof User){
return new this[name]();
}else{
return new User(name); // 处理不是按照类的实例化方式调用
}
}
User.prototype = {
admin:function(){
this.name = "admin";
this.show = function(){
console.log("欢迎管理员登陆!");
}
},
test:function(){
this.name = "test";
this.show = function(){
console.log("欢迎测试员登陆!");
}
}
}
抽象工厂模式
在工厂中定义父类集,并定义要子类需要实现的方法。父类无法在实例化中调用这些方法。
单例模式
只允许实例化一次的对象类。
命名空间方式定义居多:
let User = {
setName:function(name){
this.name = name;
},
getName:function(){
return this.name;
}
}
立即执行函数进行延迟调用创建:
let User = (function(){
let instance = null;
function CreateUser(){
return {
setName:function(name){
this.name = name;
},
getName:function(){
return this.name;
}
}
}
return function(){
if(!instance){
instance = CreateUser();
}
return instance;
}
})();
适配器 模式
解决差异,适配两个组件代码中不同的部分;
比如在处理数据格式时:
// 如果调用者传入对象方式
function User(obj){
let info = {
name:obj.name,
age:obj.age
}
// 其他引用属性处理的逻辑 info.name
}
// 如果他改为数组方式传递
function User(arr){
let info = {
name:arr[0],
age:arr[1]
}
// 其他引用属性处理的逻辑 info.name
}
改动的只有适配格式的那一块代码,后面的大量逻辑代码中使用的变量不会受到影响。
观察者模式
解决模块间的通信问题,保持数据同步。
function Observer(){
let message = {}; // 消息队列
return {
regist:function(type,callback){
// 注册事件 接受两个参数 事件类型、处理函数
if(message[type]){
message[type].push(callback);
}else{
message[type] = [callback];
}
},
publish:function(type,args){
// 发布事件 接受两个参数 事件类型、处理参数
if(!message[type]){
return;
}
let list = message[type];
for(let i=0,len = list.length;i<len;i++){
list[i].call(this,args);
}
},
remove:function(type,callback){
// 注销方法,
if(message[type] instanceof Array){
let list = message[type];
for(let len = list.length, i=len-1;i>-1;i--){
list[i] === callback&&list.splice(i,1);
}
}
}
}
}
//
let User = Observer();
User.regist("test",function(){console.log("test")});
User.publish("test","aaa");
委托模式
把多个对象接受统一处理请求都委托给另一个对象处理。
常见的给列表项加点击事件:
let items = document.getElementsByTagName("li");
for(let i=0;i<items.length;i++){
items[i].onclick = function(e){ // 给每一个li 项都加了点击事件
console.log(e.target.innerHTML);
}
}
// 利用事件冒泡给事件元素的父元素添加点击事件,通过对比事件源分类处理
let parent = document.getElementsByTagName("ul");
parent[0].onclick = function(e){ // 这样只需要添加一次事件减少内存消耗
console.log(e.target.innerHTML);
}
JQuery
中的事件监听方法就是委托模式on
,可以给动态添加的元素添加点击事件。
之前写过的文章中提到过处理动态DOM元素事件添加
jquery实现级联遇到的ajax同步请求、动态DOM元素监听事件
参考资料:
- JavaScript 设计模式