1.单例形式
单例形式的中心:
(1)确保只要一个实例
(2)供应全局接见
用代办完成单例形式:
var ProxySingletonCreateDiv = (function(){
var instance;
return function( html ){
if ( !instance ){
instance = new CreateDiv( html );
}
return instance;
}
})();
通用的惰性单例形式:建立上岸悬浮窗
//fn保留建立逻辑
//单例形式:只建立一次
var getSingle = function( fn ){
var result;
return function(){
return result || ( result = fn .apply(this, arguments ) );
}
};
var createLoginLayer = function(){
var div = document.createElement( 'div' );
div.innerHTML = '我是登录浮窗';
div.style.display = 'none';
document.body.appendChild( div );
return div;
};
var createSingleLoginLayer = getSingle( createLoginLayer );
document.getElementById( 'loginBtn' ).onclick = function(){
var loginLayer = createSingleLoginLayer();
loginLayer.style.display = 'block';
};
2.宣布-定阅者形式
(1)首先要指定好谁充任宣布者
(2)然后给宣布者增添一个缓存列表,用于寄存回调函数以便关照定阅者
(3)末了宣布音讯的时刻,宣布者会遍历这个缓存列表,顺次触发内里寄存的定阅者函数
var Event = (function(){
var clientList = {},
listen,
trigger,
remove;
listen = function( key, fn ){
if ( !clientList[ key ] ){
clientList[ key ] = [];
}
clientList[ key ].push( fn );
};
trigger = function(){
var key = Array.prototype.shift.call( arguments ),
fns = clientList[ key ];
if ( !fns || fns.length === 0 ){
return false;
}
for( var i = 0, fn; fn = fns[ i++ ]; ){
fn.apply( this, arguments );
}
};
remove = function( key, fn ){
var fns = clientList[ key ];
if ( !fns ){
return false;
}
if ( !fn ){
fns && ( fns.length = 0 );
}else{
for ( var l = fns.length - 1; l >=0; l-- ){
var _fn = fns[ l ];
if ( _fn === fn ){
fns.splice( l, 1 );
}
}
}
};
return {
listen: listen,
trigger: trigger,
remove: remove
}
})();
给一切的对象都动态装置一个宣布-定阅功用:
var installEvent = function( obj ){
for ( var i in event ){
obj[ i ] = event[ i ];
}
};
3.装潢着形式
(1)装潢者形式能够动态的给某个对象增添一些分外的职责,而不会影响从这个类中派生出的其他对象。
(2)装潢者也是包装器:装潢者形式将一个对象嵌入到另一个对象中,实际上相当于这个对象被另一个对象包装起来,构成一条包装链。
3-1.在不转变本来函数的情况下给函数增添新的功用
var a=function(){
alert(1);
}
var _a = a;
a=function(){
_a();
alert(2);
}
然则如许做会带来两个题目:必需庇护_a这个中心变量;存在this被挟制的题目
3-2.用AOP装潢函数
Function.prototype.before = function( beforefn ){
var __self = this; // 保留原函数的援用
return function(){ // 返回包含了原函数和新函数的"代办"函数
beforefn.apply( this, arguments ); // 实行新函数,且保证this 不被挟制,新函数接收的参数
// 也会被一成不变地传入原函数,新函数在原函数之前实行
return __self.apply( this, arguments ); // 实行原函数并返回原函数的实行效果,
// 而且保证this 不被挟制
}
}
Function.prototype.after = function( afterfn ){
var __self = this;
return function(){
var ret = __self.apply( this, arguments );
afterfn.apply( this, arguments );
return ret;
}
};
//挪用:重写本来函数
formSubmit = formSubmit.before( validata );
4.战略形式
战略形式的定义是:定义一系列的算法,把它们一个个封装起来,而且使它们能够互相替代。
4-1.运用战略形式盘算奖金
绩效为S的人年终奖金是工资的4倍,绩效为A的人年终奖金是工资的3倍,绩效为B的人年终奖金是工资的2倍
var performanceS = function(){};
performanceS.prototype.calculate = function( salary ){
return salary * 4;
};
var performanceA = function(){};
performanceA.prototype.calculate = function( salary ){
return salary * 3;
};
var performanceB = function(){};
performanceB.prototype.calculate = function( salary ){
return salary * 2;
};
//接下来定义奖金类Bonus:
var Bonus = function(){
this.salary = null; // 原始工资
this.strategy = null; // 绩效品级对应的战略对象
};
Bonus.prototype.setSalary = function( salary ){
this.salary = salary; // 设置员工的原始工资
};
Bonus.prototype.setStrategy = function( strategy ){
this.strategy = strategy; // 设置员工绩效品级对应的战略对象
};
Bonus.prototype.getBonus = function(){ // 获得奖金数额
return this.strategy.calculate( this.salary ); // 把盘算奖金的操纵托付给对应的战略对象
};
var bonus = new Bonus();
bonus.setSalary( 10000 );
bonus.setStrategy( new performanceS() ); // 设置战略对象
console.log( bonus.getBonus() ); // 输出:40000
4-2.javascript版本的战略形式
var strategies = {
"S": function( salary ){
return salary * 4;
},
"A": function( salary ){
return salary * 3;
},
"B": function( salary ){
return salary * 2;
}
};
var calculateBonus = function( level, salary ){
return strategies[ level ]( salary );
};
console.log( calculateBonus( 'S', 20000 ) ); // 输出:80000
console.log( calculateBonus( 'A', 10000 ) ); // 输出:30000
经由过程运用战略形式重构代码,我们消除了本来顺序中大片的前提分支代码。一切和盘算奖金的逻辑不再放在context中,而是散布在各个战略对象中。每一个战略对象担任的算法已被各自封装在对象内部。当我们对这些战略对象发出“盘算奖金”要求时,它们会返回各自差别的盘算效果。
4-3.用战略形式举行表单校验
(1)用户名不能为空
(2)暗码长度不能少于6位
(3)手机号码必需相符花样
<html>
<body>
<form action="http:// xxx.com/register" id="registerForm" method="post">
请输入用户名:<input type="text" name="userName"/ >
请输入暗码:<input type="text" name="password"/ >
请输入手机号码:<input type="text" name="phoneNumber"/ >
<button>提交</button>
</form>
<script>
/***********************战略对象**************************/
var strategies = {
isNonEmpty: function( value, errorMsg ){
if ( value === '' ){
return errorMsg;
}
},
minLength: function( value, length, errorMsg ){
if ( value.length < length ){
return errorMsg;
}
},
isMobile: function( value, errorMsg ){
if ( !/(^1[3|5|8][0-9]{9}$)/.test( value ) ){
return errorMsg;
}
}
};
/***********************Validator 类**************************/
var Validator = function(){
this.cache = [];
};
Validator.prototype.add = function( dom, rules ){
var self = this;
for ( var i = 0, rule; rule = rules[ i++ ]; ){
(function( rule ){
var strategyAry = rule.strategy.split( ':' );
var errorMsg = rule.errorMsg;
self.cache.push(function(){
var strategy = strategyAry.shift();
strategyAry.unshift( dom.value );
strategyAry.push( errorMsg );
return strategies[ strategy ].apply( dom, strategyAry );
});
})( rule )
}
};
Validator.prototype.start = function(){
for ( var i = 0, validatorFunc; validatorFunc = this.cache[ i++ ]; ){
var errorMsg = validatorFunc();
if ( errorMsg ){
return errorMsg;
}
}
};
/***********************客户挪用代码**************************/
var registerForm = document.getElementById( 'registerForm' );
var validataFunc = function(){
var validator = new Validator();
validator.add( registerForm.userName, [{
strategy: 'isNonEmpty',
errorMsg: '用户名不能为空'
}, {
strategy: 'minLength:6',
errorMsg: '用户名长度不能小于10 位'
}]);
validator.add( registerForm.password, [{
strategy: 'minLength:6',
errorMsg: '暗码长度不能小于6 位'
}]);
var errorMsg = validator.start();
return errorMsg;
}
registerForm.onsubmit = function(){
var errorMsg = validataFunc();
if ( errorMsg ){
alert ( errorMsg );
return false;
}
};
</script>
</body>
</html>
5.代办形式
代办形式是为一个对象供应一个代用品或占位符,以便掌握对它的接见。
5-1.小明追女神的故事
小明遇到了他的女神A,盘算送一朵鲜花来表白。恰好小明探询探望到他和A有一个配合的挚友B,因而小明决议让B来替本身来完成这件事。
var Flower = function(){};
var xiaoming = {
sendFlower: function( target ){
var flower = new Flower();
target.receiveFlower( flower );
}
};
var A = {
receiveFlower: function( flower ){
console.log( '收到花 ' + flower );
}
};
xiaoming.sendFlower( A );
//接下来,我们引入代办B,即小明经由过程B 来给A 送花:
var Flower = function(){};
var xiaoming = {
sendFlower: function( target){
var flower = new Flower();
target.receiveFlower( flower );
}
};
var B = {
receiveFlower: function( flower ){
A.receiveFlower( flower );
90 第6 章 代办形式
}
};
var A = {
receiveFlower: function( flower ){
console.log( '收到花 ' + flower );
}
};
xiaoming.sendFlower( B );
//然后挑选A 心境好的时刻把花转交给A,代码以下:
var Flower = function(){};
var xiaoming = {
sendFlower: function( target){
var flower = new Flower();
target.receiveFlower( flower );
}
};
var B = {
receiveFlower: function( flower ){
A.listenGoodMood(function(){ // 监听A 的好心境
A.receiveFlower( flower );
});
}
};
var A = {
receiveFlower: function( flower ){
console.log( '收到花 ' + flower );
},
listenGoodMood: function( fn ){
setTimeout(function(){ // 假定10 秒以后A 的心境变好
fn();
}, 10000 );
}
};
xiaoming.sendFlower( B );
var myImage = (function(){
var imgNode = document.createElement( 'img' );
document.body.appendChild( imgNode );
return {
setSrc: function( src ){
imgNode.src = src;
}
}
})();
5-2.庇护代办与假造代办
庇护代办:比方B能够协助A过滤掉一些要求,如送花的人中岁数较大的
假造代办:new Flower多是异常高贵的,这时刻须要B代办去实行,代办B在A心境好的时刻再实行。
5-3.假造代办完成图片预加载
var myImage = (function(){
var imgNode = document.createElement( 'img' );
document.body.appendChild( imgNode );
return function( src ){
imgNode.src = src;
}
})();
var proxyImage = (function(){
var img = new Image;
img.onload = function(){
myImage( this.src );
}
return function( src ){
myImage( 'file:// /C:/Users/svenzeng/Desktop/loading.gif' );
img.src = src;
}
})();
proxyImage( 'http:// imgcache.qq.com/music// N/k/000GGDys0yA0Nk.jpg' );
纵观全部顺序,我们并没有转变或许增添myImage接口,然则经由过程代办对象,实际上是给体系增添了新的行动:给img节点设置 src和图片预加载这两个功用。
5-4.假造代办兼并http要求
<body>
<input type="checkbox" id="1"></input>1
<input type="checkbox" id="2"></input>2
<input type="checkbox" id="3"></input>3
<input type="checkbox" id="4"></input>4
<input type="checkbox" id="5"></input>5
<input type="checkbox" id="6"></input>6
<input type="checkbox" id="7"></input>7
<input type="checkbox" id="8"></input>8
<input type="checkbox" id="9"></input>9
</body>
script.js:
var synchronousFile = function( id ){
console.log( '最先同步文件,id 为: ' + id );
};
var proxySynchronousFile = (function(){
var cache = [], // 保留一段时间内须要同步的ID
timer; // 定时器
return function( id ){
cache.push( id );
if ( timer ){ // 保证不会掩盖已启动的定时器
return;
}
timer = setTimeout(function(){
synchronousFile( cache.join( ',' ) ); // 2 秒后向本体发送须要同步的ID 鸠合
clearTimeout( timer ); // 清空定时器
timer = null;
cache.length = 0; // 清空ID 鸠合
}, 2000 );
}
})();
var checkbox = document.getElementsByTagName( 'input' );
for ( var i = 0, c; c = checkbox[ i++ ]; ){
c.onclick = function(){
if ( this.checked === true ){
proxySynchronousFile( this.id );
}
}
};