《JavaScript设计模式》笔记 - - - 超全设计模式概览

该篇文章用于记录阅读《JavaScript设计模式》后归纳的读书笔记,主要以代码形式进行展示,用于快速回顾对应设计模式的代码构造

1.面向对象编程

1.使用对象收编变量

优点:避免全局变量冲突与覆盖
缺点:不利于复用

var CheckObj = {checkName: fucntion() {},checkEmail: fucntion() {},
}CheckObj.checkName()

2.使用类定义

优点:功能可被复用
缺点:每个对象都有方法,造成消耗

var CheckObj = function() {this.checkName = fucntion() {},this.checkEmail = fucntion() {},
}var a = new CheckObj()
a.checkName()

3.使用原型链

优点:对象调用的都是同一个方法,减少消耗

var CheckObj = function() {}
CheckObj.prototype = {checkName = fucntion() {return this  // 返回this便于连续调用},checkEmail = fucntion() {return this},
}

4.函数式对象

var Book = function(id, name, price) {// 私有变量var num = 1;// 私有方法function checkId () {}// 特权方法:对象通过该方法访问私有属性和调用私有方法this.getName = function() {}this.getPrice = function() {}this.setName = function() {}this.setPrice = function() {}// 公用变量this.id = id// 公用方法this.clone = function() {}// 构造器this.setName(name)this.setPrice(price)
}// 类静态公有变量,通过类访问,不可通过对象访问
Book.isChinese = true
Book.resetTime = function() {}// 原型上属于对象公有变量,可通过对象访问
Book.prototype = {isJSBook: flase
}

5.闭包函数

var Book = (function() {// 静态私有变量,仅闭包内可访问var bookNum = 0;// 静态私有方法,仅闭包内可访问function checkBook(name) { }// 创建闭包类function _book(id, name, price) {// 私有变量var num = 1;// 私有方法function checkId () {}// 特权方法:对象通过该方法访问私有属性和调用私有方法this.getName = function() {}this.getPrice = function() {}this.setName = function() {}this.setPrice = function() {}// 公用变量this.id = id// 公用方法this.clone = function() {}// 构造器this.setName(name)this.setPrice(price)}_book.prototype = {isJSBook: flase}return _book;
})()

6.创建对象的安全模式

避免因为new的遗漏导致新建不必要的全局变量

var Book = function(id, name, price) {if(this instanceof Book) {this.id = idthis.name = namethis.price = price}else return new Book(id, name, price)
}var book = Book('1', 'JS', '32')

7.继承

类式继承:新建父类实例绑定在子类原型链上SubClass.prototype = new SuperClass()
优点:继承父类原型链
缺点:多个子类公用父类属性,子类对属性的修改相互影响

构造函数继承:子类中调用父类构造函数SuperClass.call(this, id)
优点:多个子类有不同的父类属性备份,不会相互影响
缺点:无法继承父类原型链

组合继承
优点:属性不相互影响且继承父类原型链
缺点:两次调用父类构造函数

// 组合继承示例
function SuperClass(name){this.name = name;this.books = ['html', 'css', 'javascript']
}SuperClass.prototype.getName = function() {console.log(this.name);
}function SubClass(name, time) {SuperClass.call(this, name)this.time = time
}SubClass.prototype = new SuperClass()

2.创建型设计模式

1.简单工厂模式

特性:共性赋值,针对差异进行特殊处理
差异:类直接对变量进行处理,简单工厂生产对象赋值给变量

function createPop(type, text) {var o = new Object()o.content = texto.show = function() {}if(type === 'alert') {}if(type === 'prompt') {}
}

2.工厂方法模式

优点:扩展类直接添加到原型中,不需要根据扩展对工厂函数进行修改

var Factory = function(type, content) {// 保证正确调用工厂函数if(this instanceof Factory) {var s = new this[type](content)return s} else {return new Factory(type, content)}
}Factory.prototype = {Java:function() {}JavaScript: function() {}
}

3.抽象工厂模式

优点:通过抽象类方法明确子类的类别,并且明确子类必备的属性和方法

// 定义抽象工厂,使子类能够继承抽象类
const VehicleFactory = function(subType, superType) {if (typeof VehicleFactory[superType] === 'function') {function F() {this.type = '车辆'} F.prototype = new VehicleFactory[superType]()subType.constructor = subTypesubType.prototype = new F() } else throw new Error('不存在该抽象类')
}// 定义抽象类属性
VehicleFactory.Car = function() {this.type = 'car'
}
// 定义抽象类方法,子类若不覆写则报错
VehicleFactory.Car.prototype = {getPrice: function() {return new Error('抽象方法不可使用')},getSpeed: function() {return new Error('抽象方法不可使用')}
}const BMW = function(price, speed) {this.price = pricethis.speed = speed
}
VehicleFactory(BMW, 'Car')  
BMW.prototype.getPrice = function() {console.log(`BWM price is ${this.price}`)
}
BMW.prototype.getSpeed = function() {console.log(`BWM speed is ${this.speed}`)
}const baomai5 = new BMW(30, 99)
baomai5.getPrice()                          
baomai5 instanceof VehicleFactory.Car  

4.建造者模式

特性:负责对多对象进行组建
区别:建造者模式更注重的是零件的组装过程,而工厂方法注重的是零件的创建过程

function LivingRoom(wall,tv,sofa) {var wall,tv;this.setWall = function (wall) {this.wall = wall;};this.setTv = function (tv) {this.tv = tv;this.show = function () {console.log(this.wall,this.tv,this.sofa)}
}//抽象建造者-包含创建子部件的抽象方法及返回产品的方法
function Builder() {this.product = new LivingRoom();this.getResult = function () {return this.product;}
}
Builder.prototype.buildWall = function () {}
Builder.prototype.buildTv = function () {}//具体建造者
function ConcreteBuilder() {}
ConcreteBuilder.prototype = new Builder();
ConcreteBuilder.prototype.buildWall = function (){this.product.setWall("刷墙");console.log(this.product)
};
ConcreteBuilder.prototype.buildTv = function (){this.product.setTv("安装电视");
};//指挥者
function Director(builder) {//获取产品方法this.getProduct = function () {//刷墙builder.buildWall();//安装电视builder.buildTv();//返回客厅return builder.getResult();}
}var concreteBuild = new ConcreteBuilder();
var director= new Director(concreteBuild);
var product = director.getProduct();
product.show();

5.原型模式

特性:构造函数+原型链的组合式继承
优点:将共性写在原型链中,避免多次创建重复方法

var LoopImage = function(imgArr, container) {this.imagesArray = imgArr;this.container = container;
}
LoopImage.prototype = {createImage: function() {}changeImage: function() {}
}var SlideLoopImg = fucntion(imgArr, container) {LoopImages.call(this, imgArr, container)
}
SlideLoopImg.prototype = changeImage = function() {}

6.单例模式

特性与优点
(1)仅创建单个对象并返回使用
(2)作为命名空间进行管理,避免冲突
(3)存储静态变量仅可读取不可修改

const DEFAULT_GDKey = '1993ac213d2f4675ac1bffb1b03ef1f0'
const DEFAULT_GDServiceHost = 'http://172.16.3.103:7799/_AMapService'/*** @Description: 初始化高德地图* @author: lyz
*/
class GDApi {isInit: boolean // 是否初始化key: string // 高德keyv: string // map版本uiVersion: string // UI组件库版本getNewKey() {return Storager.Setting.get('GDkey', '__system') || DEFAULT_GDKey}initial() {this.isInit = truethis.key = this.getNewKey()this.v = '1.4.19'this.uiVersion = '1.0'initAMapApiLoader({key: this.key,plugin: this.plugin,v: this.v,uiVersion: this.uiVersion})}changeMap() {let GDkey = this.getNewKey()// 未初始化则不刷新if (!this.isInit) return false// 新的高德key与原有高德key不同时刷新else if (GDkey !== this.key) return true// 其他情况则不刷新else return false}}export const gdApi = new GDApi()

3.结构型设计模式

1.外观模式

优点:不需要关注内部逻辑,只需要知道外观下的用途

function addEvent(dom, type ,fn) {if(dom.addEventListener) {dom.adEventListener(type, fn, false)} else if(dom.attachEvent) {dom.attachEvent('on' + type, fn)} else {dom['on' + type] = fn}
}

2.适配器模式

将某种形式数据通过适配器转换成合适的数据

function arrToObjAdapter(arr) {return {name: arr[0],type: arr[1],title: arr[2],data: arr[3]}
}var arr = ['JavaScript', 'book', '前端编程语言', '8月1日']
var adapterData = arrToObjAdapter(arr)

3.代理模式

代理模式进行图片懒加载,亦称虚拟代理

// 图片节点
var myImage = (function() {var imgNode = document.createElement('img');document.body.appendChild(imgNode);return {setSrc: function(src) {imgNode.src = src;}}
})();// 图片懒加载代理管理
var preImage = (function() {var img = new Image; img.onload = function() {myImage.setSrc = img.src;}; return {setSrc: function(src) {myImage.setSrc('../loading.gif');img.src = src;}}
})(); preImage.setSrc('https://cn.bing.com/az/hprichbg/rb/TadamiTrain_ZH-CN13495442975_1920x1080.jpg'); 

4.装饰者模式

优点:不需要关注原有功能,在原有功能基础上直接增加功能

var decorator = function(input, fn) {var input = document.getElementById(input)if(typeof input.onclick === 'function') {var oldClickFn = input.onclick// 获取原有点击事件响应函数,并在此基础上增加功能input.onclick = function() {oldClickFn()fn()}} else {input.onclick = fn}
}

5.桥接模式

优点:解耦抽象层与实现层,两部分独立完成

function changeColor(dom, color, bg) {dom.style.color = colordom.style.background = bg
}span[0].onmouseover = function() {changeColor(this, 'red', '#ddd')
}

6.组合模式

优点:仅需要调用组合对象便能对单个对象进行逐个调用

// 新建一个关门的命令
var closeDoorCommand = {execute: function(){console.log( '关门' );}
};
// 新建一个开电脑的命令
var openPcCommand = {execute: function(){console.log( '开电脑' );}
};
// 登陆QQ的命令
var openQQCommand = {execute: function(){console.log( '登录QQ' );}
};// 创建一个宏命令
var MacroCommand = function(){return {// 宏命令的子命令列表commandsList: [],// 添加命令到子命令列表add: function( command ){this.commandsList.push( command );},// 依次执行子命令列表里面的命令execute: function(){for ( var i = 0, command; command = this.commandsList[ i++ ]; ){command.execute();}}}
};var macroCommand = MacroCommand();
macroCommand.add( closeDoorCommand );
macroCommand.add( openPcCommand );
macroCommand.add( openQQCommand );
macroCommand.execute();

7.享元模式

优点:针对具有相同结构的大量数据,由共享对象针对不同情况存储不同数据

// 情景:全量获取数据,实现翻页功能,翻页过程中针对共享单页数据进行数据切换
var Flyweight = function() {var created = []function create() {var dom = document.createElement('div')document.getElementById('container').appendChild(dom)created.push(dom)return dom}return {getDiv: function() {if(created.length < 5) {return create()} else {var div = created.shift()created.push(div)return div}}}
}

4.行为型设计模式

1.模板方法模式

特性:抽取共同点作为基类,子类在基类的基础上进行改变

// 定义基类:将相同的步骤抽离出来作为init方法
var Beverage = function(){};
Beverage.prototype.boilWater = function(){console.log( '把水煮沸' );
};
Beverage.prototype.brew = function(){}; // 空方法,应该由子类重写
Beverage.prototype.pourInCup = function(){}; // 空方法,应该由子类重写
Beverage.prototype.addCondiments = function(){}; // 空方法,应该由子类重写
Beverage.prototype.init = function(){this.boilWater();this.brew();this.pourInCup();this.addCondiments();
};// 定义子类,子类针对不同步骤进行不同操作,但操作步骤的顺序与基类相同
var Coffee = function(){};
Coffee.prototype = new Beverage();Coffee.prototype.brew = function(){console.log( '用沸水冲泡咖啡' );
};
Coffee.prototype.pourInCup = function(){console.log( '把咖啡倒进杯子' );
};
Coffee.prototype.addCondiments = function(){console.log( '加糖和牛奶' );
};
var Coffee = new Coffee();
Coffee.init();

2.观察者模式

特性:各模块之间解耦,其他模块只需要发布通知,各模块内部接受通知后完成本模块需完成内容

var Observer = (function(){var _message = {};return {// 注册事件regist: function(type, fn) {if(typeof _message[type] === 'undefined') {_message[type] = [fn]} else {_message[type].push(fn)}},// 触发事件fire: function(type, args) {if(!_message[type]) returnelse {_message[type].forEach((item) => {item.call(this, args)})}},// 移除事件remove: function(type, fn){if(_message[type] instanceof Array) {var i = _message[type].length - 1for(; i >= 0 ; i--) {_message[type][i] === fn && _message[type].splice(i, 1)}}}}
})()

3.状态模式

特性:状态决定行为,分支语句取决于状态

class SuperMarry {constructor() {this._currentState = []this.states = {jump() {console.log('跳跃!')},move() {console.log('移动!')},shoot() {console.log('射击!')},squat() {console.log('蹲下!')}}}change(arr) {  // 更改当前动作this._currentState = arrreturn this}go() {console.log('触发动作')this._currentState.forEach(T => this.states[T] && this.states[T]())return this}
}new SuperMarry().change(['jump', 'shoot']).go()                    // 触发动作  跳跃!  射击!.go()                    // 触发动作  跳跃!  射击!.change(['squat']).go()                    // 触发动作  蹲下!

4.策略模式

特性:根据不同分支情况适用不同算法,使用与实现之间的解耦

var countPrice = {returnPrice: {full100: function (price) {return price - 5},full200: function (price) {return price - 15},full300: function (price) {return price - 30},full400: function (price) {return price - 50}},getPirce: function (type, money) {return this.returnPrice[type] ? this.returnPrice[type](money) : money;},addRule: function (type, discount) {this.returnPrice[type] = function (price) {return price - discount;}}
}

5.职责链模式

特性:业务划分为多个步骤,步骤间解耦,通过链的方式连接

// 500元订单
var order500 = function( orderType, pay, stock ){if ( orderType === 1 && pay === true ){console.log( '500元定金预购, 得到100优惠券' );}else{order200( orderType, pay, stock ); // 将请求传递给200元订单}
}
// 200元订单
var order200 = function( orderType, pay, stock ){if ( orderType === 2 && pay === true ){console.log( '200元定金预购, 得到50优惠券' );}else{orderNormal( orderType, pay, stock ); // 将请求传递给普通订单}
}
// 普通购买订单
var orderNormal = function( orderType, pay, stock ){if ( stock > 0 ){console.log( '普通购买, 无优惠券' );}else{console.log( '手机库存不足' );}
}
// 测试结果:
order500( 1 , true, 500); // 输出:500元定金预购, 得到100优惠券

6.命令模式

特性:将对象操作封装成命令,执行时只需调用对应的命令即可

class Editor {constructor() {this.content= ''}write(content) {this.content+=contentreturn this}read() {console.log(this.content)return this}space() {this.content+= ' 'return this}
}

7.访问者模式

特性:针对数据稳定,数据操作方法易变的情况,进行数据以及操作方法的解耦

var Visitor = (function() {return {splice: function() {var args = Array.prototype.splice.call(arguments, 1);return Array.prototype.splice.apply(arguments[0], args);},push: function() {var len = arguments[0].length || 0;var args = this.splice(arguments, 1);arguments[0].length = len + arguments.length - 1;return Array.prototype.push.apply(arguments[0], args);},pop: function() {return Array.prototype.pop.apply(arguments[0]);}}
})();var a = new Object();
Visitor.push(a,1,2,3,4);
Visitor.push(a,4,5,6);
Visitor.pop(a);
Visitor.splice(a,2);

8.中介者模式

特性:对象与对象之间的引用解耦合,由中介者管理对象并处理操作信息

var playerDirector= ( function(){var players = {}, // 保存所有玩家operations = {}; // 中介者可以执行的操作/****************新增一个玩家***************************/operations.addPlayer = function( player ){var teamColor = player.teamColor; // 玩家的队伍颜色players[ teamColor ] = players[ teamColor ] || []; // 如果该颜色的玩家还没有成立队伍,则新成立一个队伍players[ teamColor ].push( player ); // 添加玩家进队伍};/****************移除一个玩家***************************/operations.removePlayer = function( player ){var teamColor = player.teamColor, // 玩家的队伍颜色teamPlayers = players[ teamColor ] || []; // 该队伍所有成员for ( var i = teamPlayers.length - 1; i >= 0; i-- ){ // 遍历删除if ( teamPlayers[ i ] === player ){teamPlayers.splice( i, 1 );}}};/****************玩家换队***************************/operations.changeTeam = function( player, newTeamColor ){ // 玩家换队operations.removePlayer( player ); // 从原队伍中删除player.teamColor = newTeamColor; // 改变队伍颜色operations.addPlayer( player ); // 增加到新队伍中};operations.playerDead = function( player ){ // 玩家死亡var teamColor = player.teamColor,teamPlayers = players[ teamColor ]; // 玩家所在队伍var all_dead = true;for ( var i = 0, player; player = teamPlayers[ i++ ]; ){if ( player.state !== 'dead' ){all_dead = false;break;}}if ( all_dead === true ){ // 全部死亡for ( var i = 0, player; player = teamPlayers[ i++ ]; ){player.lose(); // 本队所有玩家lose}for ( var color in players ){if ( color !== teamColor ){var teamPlayers = players[ color ]; // 其他队伍的玩家for ( var i = 0, player; player = teamPlayers[ i++ ]; ){player.win(); // 其他队伍所有玩家win}}}}};var ReceiveMessage = function(){var message = Array.prototype.shift.call( arguments ); // arguments的第一个参数为消息名称operations[ message ].apply( this, arguments );};return {ReceiveMessage: ReceiveMessage}
})();

9.备忘录模式

特性:缓存状态信息,在切换时直接获取原状态,减少网络请求

var Page = function() {var cache = {}return function(page, fn) {if(cache[page]) {showPgae(page, cache[page])fn && fn()} else  {proxy.$http.post(url, param).then((result) => {showPage(page, res.data)cahce[page] = res.datafn && fn()})}}
}

10.迭代器模式

特性:提供方法顺序访问一个聚合对象

class Iterator {constructor(conatiner) {this.list = conatiner.listthis.index = 0}next() {if (this.hasNext()) {return this.list[this.index++]}return null}hasNext() {if (this.index >= this.list.length) {return false}return true}
}

11.解释器模式

// 例子:返回元素的文档路径,根据需求解析出语法规则
function getSiblingName(node) {if (node.previousSibling) {var name = '';var count = 1;var nodeName = node.nodeName;var sibling = node.previousSibling;while (sibling) {// 元素节点并且类型相同并且有名字if (sibling.nodeType === 1 && sibling.nodeType === node.nodeType && sibling.nodeName) {if (nodeName === sibling.nodeName) {count++;name += count;} else {count = 1;name += '|' + sibling.nodeName.toUpperCase();}}sibling = sibling.previousSibling;}return name;} else {// 不存在就返回空字符串了return '';}
}var Interpreter = (function() {return function(node, wrap) {var path = [];wrap = wrap || document;// 处理特殊情况if (node === wrap) {if (wrap.nodeType === 1) {path.push(wrap.nodeName.toUpperCase());}return path;} else if (node.parentNode !== wrap) {path = arguments.callee(node.parentNode, wrap);} else {if (wrap.nodeType === 1) {path.push(wrap.nodeName.toUpperCase());}}var sublingsNames = getSiblingName(node);if (node.nodeType === 1) {path.push(node.nodeName.toUpperCase() + sublingsNames);}return path;}
})();
window.onload = function() {var path = Interpreter(document.getElementById('button'));alert(path);
}

5.技巧型设计模式

1.链模式

特性:通过点语法对对象方法进行链式调用

// 例子:jQuery实现
function _jQuery(selector){return new _jQuery.fn.init(selector); // new复制避免共用同一个对象
}
_jQuery.fn = _jQuery.prototype = {constructor: _jQuery,init: function(selector){this[0] = document.querySelector(selector);this.length = 1;return this;},length: 3,size: function(){return this.length;}
}
// new返回的是_jQuery.fn.init的实例,无法链式调用方法,调整原型指向
_jQuery.fn.init.prototype = _jQuery.fn;

2.委托模式

特性:解决请求与委托者之间的耦合关系,被委托者接收请求分发给委托者

// 例子:父元素通过冒泡监听点击事件,对触发点击事件的子元素进行操作,不需要给每个子元素都绑定点击事件。避免内存泄漏(清除元素时未清除事件)ul.onclick = function(e) {// console.log(e.target)// 进行判定点击的是哪个元素if (e.target.nodeName.toLowerCase() === "span") {// 此时e.target是spanthis.removeChild(e.target.parentNode);} else if (e.target.nodeName.toLowerCase() === "li") {// 此时e.target是lie.target.style.backgroundColor = "red"}
}

3.数据访问模式

特性:对数据库操作进行封装

/*** LocalStorage数据访问类* @param {string} prefix Key前缀* @param {string} timeSplit 时间戳与存储数据之间的分割符*/
var Dao = function (prefix, timeSplit) {this.prefix = prefix;this.timeSplit = timeSplit || '|-|';
}
// LocalStorage数据访问类原型方法
Dao.prototype = {// 操作状态status: {SUCCESS: 0,     // 成功FAILURE: 1,     // 失败OVERFLOW: 2,    // 溢出TIMEOUT: 3      // 过期},// 本地存储对象storage: localStorage || window.localStorage,// 获取带前缀的真实键值getKey: function (key) {return this.prefix + key;},// 添加(修改)数据set: function (key, value, callback, time) {...},// 获取数据get: function (key, callback) {...},// 删除数据remove: function (key, callback) {...}
}

4.节流模式

特性:针对短时间内多次触发的事件进行节流

var throttle = function f() {arguments.slice = Array.prototype.slice;var fn,params=[];//如果第一个参数是boolean类型那么第一个参数表示清除定时器if(typeof arguments[0] === 'boolean') {//第二个参数为函数fn = arguments[1];//函数的计时器句柄存在,清除该定时器fn.__throttleID && clearTimeout(fn. __throttleID);//工作计时器延迟执行函数} else {fn = arguments[0];params = arguments.slice(1);f(true,fn);//为函数绑定句柄函数fn.__throttleID = setTimeout(function() {//执行函数fn.apply(null, params);}, 500)}
}

5.简单模板模式

生成视图模板字符串插入视图中,避免对DOM的多次操作

// 模板生成器
A.view = function(name){var v = {code : '<pre><code>{#code#}</code></pre>',img : '<img src="{#src#}" alt="{#alt#}" title="{#title#}" />',part : '<div id="{#id#}" class="{#class#}">{#part#}</div>',theme : ['<div>','<h1>{#title#}</h1>','{#content#}','</div>'].join('')}if(Object.prototype.toString.call(name) === "[object Array]"){//模板缓存器var tpl = '';for(var i=0;i<name.length;i++){tpl += arguments.callee(name[i]);}return tpl;}else{//如果模板库中有该模板就返回,否则返回简易模板return v[name] ? v[name] : ('<'+name+'>{#'+name+'#}<'+name='>');}
}
// 模板字符串赋值
A.formateString = function(str, data) {return str.replace(/\{#(\w+)#\}/g, function(match, key) {retun typeof data[key] === undefined ? '' : data[key]})
}

6.惰性模式

特性:对象创建需要重复分支判断的情况,每次返回结果都为固定唯一

// 例子:运用闭包,加载时确定分支
var AddEvent = function(dom, type, fn){if(dom.addEventListener){return function(dom, type, fn){dom.addEventListener(type, fn, false);}}else if(dom.attachEvent){return function(dom, type, fn){dom.attachEvent('on'+type, fn);}}else{return function(dom, type, fn){dom['on'+type] = fn;}}
}();// 例子:第一次调用时确定分支
var AddEvent = function(dom, type, fn){if(dom.addEventListener){AddEvent = function(dom, type, fn){dom.addEventListener(type, fn, false);}}else if(dom.attachEvent){AddEvent = function(dom, type, fn){dom.attachEvent('on'+type, fn);}}else{AddEvent = function(dom, type, fn){dom['on'+type] = fn;}}AddEvent(dom, type, fn);
};

7.参与者模式

特性:函数绑定 + 函数柯里化
函数柯里化:初始化时保存一部分参数,执行时接受一部分参数,最后返回所有参数共同执行的结果

function bind(fn, ctx /*ctx:作用域*/) {const slice = Array.prototype.slice // 保存数组原型上的slice方法,用来分割argumentsconst args = slice.call(arguments, 2) // 从第3个参数开始切割,因为前2个参数是fn和ctxreturn function () {const addArguments = slice.call(arguments) // 这里的arguments是返回的这个匿名函数的,是个空数组allArguments = addArguments.concat(args) // 数组拼接,拼接后的数组中保存的就是我们要传递的参数return fn.apply(ctx, allArguments)}
}const P1 = function(name){console.log(name)
}
const P2 = function(name,age){console.log(name,age)
}
const P1_bind = bind(P1,this,'老六')
const P2_bind = bind(P2,this,'老六',18)P1_bind() // 老六
P2_bind() // 老六,18

8.等待者模式

特性:处理耗时较长的多个操作,进行统一的状态管理,全部成功/单个失败时执行

function Waiter() {var dfd = [],// 成功的回调doneArr = [],// 失败的回调failArr = [],slice = Array.prototype.slice,that = this;var Promise = function() {this.resolved = false;this.rejected = false;};Promise.prototype = {// 全部成功则清空监听对象并执行成功函数resolve: function() {this.resolved = true;if (!dfd.length) return;for (var i = dfd.length - 1; i >= 0; i--) {if (dfd[i] && !dfd[i].resolved || dfd[i].rejected) {return;}dfd.splice(i, 1);}_exec(doneArr);},// 失败一个则清空监听对象并执行失败函数reject: function() {this.rejected = true;if (!dfd.length) return;// 失败清除全部监控对象dfd.splice(0);_exec(failArr);}};// 创建监听对象that.Deferred = function() {return new Promise();};// 执行一个失败/全部成功的回调函数function _exec(arr) {var i = 0, len = arr.length;for (; i < len; i++) {try {arr[i] && arr[i]();} catch (e) {}}}// 将监听对象放入等待者监听数组中that.when = function() {dfd = slice.call(arguments);var i = dfd.length;for (--i; i >= 0; i--) {if (!dfd[i] || dfd[i].resolved || dfd[i].rejected || !dfd[i] instanceof Promise) {dfd.splice(i, 1);}}return that;};// 将成功回调函数放入等待者执行数组中that.done = function() {doneArr = doneArr.concat(slice.call(arguments));return that;};// 将失败回调函数放入等待者执行数组中that.fail = function() {failArr = failArr.concat(slice.call(arguments));return that;}
}// 实际运用
var waiter = new Waiter();function first(waiter) {var dtd = waiter.Deferred();setTimeout(function() {console.log('first finish');dtd.resolve();},500);return dtd;
}function second(waiter) {var dtd = waiter.Deferred();setTimeout(function() {console.log('second finish');dtd.resolve();},2000);return dtd;
}waiter.when(first(waiter), second(waiter)).done(function() {console.log('all finished')
})

6.架构型设计模式

  • 同步模块模式:划分模块,同步加载对应模块
  • 异步模块模式:划分模块,异步加载对应模块
  • widget模式:将视图拆分成组件,组件合成完整视图
  • MVC模式:模型层/视图层/控制器层分别工作,减少耦合
  • MVP模式:模型层/视图层/管理器层,减少模型与视图的耦合,对数据的操作统一由管理器完成
  • MVVM模式:模型层/视图层/视图模型层,视图绑定数据决定视图渲染

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/135909.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

《童年》 思维导图

《童年》是高尔基自传体小说三部曲中的第一部&#xff0c;讲述的是高尔基幼年丧父、母亲改嫁&#xff0c;他跟随日渐破落的小染坊主外公以及外婆生活的童年经历。小说通过一个儿童天真无邪的眼光&#xff0c;向读者生动地展示了19世纪中叶俄罗斯社会底层人民的生活状态&#xf…

[HCTF 2018]WarmUp最详细解释

查看源码找到提示 访问source.php 代码审计&#xff1a; class emmm{public static function checkFile(&$page){$whitelist ["source">"source.php","hint">"hint.php"]; 定义了一个名为emmm的类&#xff0c;在该类中有…

使用create-react-app脚手架创建react项目

查看npx版本&#xff1a; npx -v使用如下命令创建项目时&#xff1a; npx create-react-app demo报错&#xff1a; 解决&#xff1a; 以管理员身份运行cmd 然后再次创建项目&#xff0c;又报错&#xff1a; 经查得知&#xff1a;发生此错误是因为用户名中有空格&#xff0c;…

Linux下找出吃内存的方法

几个 个 Linux 内存查看方法 1、free命令 2、 vmstat命令 3、 /proc/meminfo 命令 4、 top命令 5、 htop 命令 6、查看进程内存信息 内存性能指标 系统内存使用情况&#xff0c;比如已用内存、剩余内存、共享内存、可用内存、缓存和缓冲区的用量等。 共享内存是通过 tmp…

detectron2环境搭建及自定义coco数据集(voc转coco)训练

detectron2建议ubuntu进行环境搭建&#xff0c;Windows大概率报错 一 环境搭建 创建虚拟环境 conda create -n detectron2 python3.8 -y conda activate detectron2后面下载源代码建议存到git中再git clone git clone https://github.com/facebookresearch/detectron2.git …

Python中的del用法

大家早好、午好、晚好吖 ❤ ~欢迎光临本文章 如果有什么疑惑/资料需要的可以点击文章末尾名片领取源码 python中的del用法比较特殊&#xff0c;新手学习往往产生误解&#xff0c;弄清del的用法&#xff0c;可以帮助深入理解python的内存方面的问题。 python的del不同于C的fre…

大厂真题:【位运算】米哈游2023秋招-相加异或

题目描述与示例 题目描述 对于一个数组c&#xff0c;定义f(c)为c数组所有元素的总和。 现在给定两个长度为n的数组a, b&#xff0c;请你恰好删除一个数组a的元素或者一个数组b的元素&#xff0c;使得f(a)异或f(b)最大。 输入描述 第一行输入一个整数n。 第二行输入n个整数…

Davinci报警汇总

问题号模块软件影响90220LDCOMCfgcheck不过&#xff0c;需要解决53006RTECfg不需要管40316Mode Declaration GroupsDev不需要管40333Application Port InterfacedDev不需要管40334Application Port InterfacedDev不需要管40339Application Port InterfacedDev不需要管40041Appl…

使用Drupal管理小型项目?试试Docker快速部署Drupal结合内网穿透实现远程访问

&#x1f3ac; 鸽芷咕&#xff1a;个人主页 &#x1f525;个人专栏:《Linux深造日志》《C干货基地》 ⛺️生活的理想&#xff0c;就是为了理想的生活! 文章目录 前言1. Docker安装Drupal2. 本地局域网访问3 . Linux 安装cpolar4. 配置Drupal公网访问地址5. 公网远程访问Drupal…

SUSE 12双网卡绑定

原创作者&#xff1a;运维工程师 谢晋 SUSE 12双网卡绑定 客户环境及需求网卡绑定 客户环境及需求 客户一台物理机安装了SUSE 12的操作系统&#xff0c;需要将ETH5和ETH7双网卡聚合为一块虚拟网卡&#xff0c;以保证一块网卡故障不会影响系统正常运行。 网卡绑定 输入命令c…

HBase学习笔记(1)—— 知识点总结

目录 HBase概述 HBase 基本架构 HBase安装部署启动 HBase Shell HBase数据读写流程 HBase 优化 HBase概述 HBase是以 hdfs 为数据存储的&#xff0c;一种分布式、非关系型的、可扩展的 NoSQL 数据库 关系型数据库和非关系型数据库的区别&#xff1a; 关系型数据库和非关…

windows系统自动更新中断电导致系统无法开启

windows系统自动更新中断电导致系统无法开启 现象原因解决进入bios拆机更新系统重新安装内存条 现象 前一天晚上电脑出现合上之后风扇继续转的现象&#xff0c;拔掉电源后&#xff0c;第二天开不了机。现象为按压电源键&#xff0c;电源键和充电指示灯亮一次后熄灭&#xff0c…

每天一点python——day65

#每天一点Python——65 #字符串的内容对齐操作类似于word中左对齐、右对齐、居中对齐如图 #例&#xff1a; s1hello,python print(s1.center(20,*))#设置宽度20&#xff0c;填充图是*s1有12个字符&#xff0c;这个字符串的宽度设置为20&#xff0c; 20-128 因为center是居中对齐…

后端面试问题(学习版)

JAVA相关 JAVA语言概述 1. 一个".java"源文件中是否可以包含多个类&#xff1f;有什么限制&#xff1f; 可以。 一个源文件可以声明多个类&#xff0c;但是最多只能有一个类使用public进行声明 且要求声明public的类的类名与源文件相同。 2. Java的优势&#xff…

MySQL进阶_1.逻辑架构和SQL执行流程

文章目录 第一节、逻辑架构剖析1.1、服务器处理客户端请求1.2、Connectors1.3、第1层&#xff1a;连接层1.4、第2层&#xff1a;服务层1.5、 第3层&#xff1a;引擎层1.6、 存储层1.7、小结 第二节、SQL执行流程2.1、查询缓存2.2、解析器2.3、优化器2.4、执行器 第三节、数据库…

安装dubbo-admin报错node版本和test错误

✅作者简介&#xff1a;CSDN内容合伙人、信息安全专业在校大学生&#x1f3c6; &#x1f525;系列专栏 &#xff1a;dubbo-admin安装 &#x1f4c3;新人博主 &#xff1a;欢迎点赞收藏关注&#xff0c;会回访&#xff01; &#x1f4ac;舞台再大&#xff0c;你不上台&#xff0…

【Linux】进程的基本概念和进程控制

TOC 目录 一.冯诺依曼体系结构 二. 操作系统(Operator System) 概念 设计OS的目的 定位 总结 系统调用和库函数概念 进程 基本概念 描述进程-PCB task_struct-PCB的一种 task_ struct内容分类 组织进程 查看进程 通过系统调用获取进程标识符 进程状态 D--深度…

【笔记】原型和原型链(持续完善)

概念 原型&#xff1a;函数都具有 prototype 属性&#xff0c;称之为原型&#xff0c;也称之为原型对象 1.1 原型可以放一些属性和方法&#xff0c;共享给实例对象使用&#xff08;也就是原生方法&#xff09;。 1.2 原型可以做继承原型链&#xff1a;对象都有 __proto__ 属性…

Qt 4.8.6 的下载与安装

Qt 4.8.6 的下载与安装 Qt 4.8.6 的下载与安装下载并解压 MinGW 4.8.2Qt4.8.6 库的安装Qt Creator 3.3.0 的安装配置 Qt Creator测试 Qt 4.8.6 的下载与安装 学习《Qt Creator快速入门》&#xff08;第3版&#xff09;&#xff0c;书里面要用 Qt:phonon&#xff0c;这个组件要…