单例模式
- 保证一个类只有一个实例,并提供一个访问他的全局访问点;
模拟单例实现
var createDiv = (function(){
var instance;
var createDiv = function(html){
if(instance)
return instance;
this.html = html;
this.init();
return instance = this;
};
createDiv.prototype.init = function() {
var div = document.createElement('div');
div.innerHTML = this.html;
document.body.appendChild(div);
};
return createDiv;
})();
var createDiv = function(html) {
this.html = html;
this.init();
};
createDiv.prototype.init = function() {
var div = document.createElement('div');
div.innerHTML = this.html;
document.body.appendChild(div);
};
var proxyCreateDiv = (function(){
var instance;
return function(html) {
if(instance)
return instance;
return new CreateDiv(html);
}
})();
JS中的单例模式
- 传统模式中单例对象从类中创建而来,但JS其实并无类;
- 抓做单例模式核心:确保只有一个可全局访问的实例;可以用更符合JS的方式创建
- 使用命名空间
var MyApp = {};
MyApp.namespace = function(name) {
var parts = name.split('.'),
current = MyApp;
for(prop in parts) {
if(!current[parts[prop]])
current[parts[prop]] = {};
current = current[parts[prop]];
}
}
var user = (function() {
var _name = 'jinks',
_age = 23;
return { //对象返回
getUserInfo: function() {
return _name + ' ' + _age;
}
}
})();
惰性单例
- 即只在需要的时候才创建的单例对象实例
- 优化把创建实例对象和管理单例分开
/**
* 点击创建|显示|隐藏div
*/
var getSingle = function (fn) {
var result;
return function() {
return result || (result = fn.apply(this, arguments))
}
};
var createDiv = function(name, id) {
var div = document.createElement('div');
div.innerHTML = name;
div.id = id;
div.style.display = 'none';
document.body.appendChild(div);
return div;
};
var divChange = function(fn,name,id) {
var div = fn(name,id);
var display = div.style.display;
div.style.display = display === 'none' ? 'block' : 'none';
};
divElem = {
div1: getSingle(createDiv),
div2: getSingle(createDiv)
};
document.getElementById('div1Btn').onclick = function () {
divChange(divElem.div1,'div1','div1');
};
document.getElementById('div2Btn').onclick = function () {
divChange(divElem.div2,'div2','div2');
};
var bindEvent = getSingle(function() {
document.getElementById('click').onclick = function() {
alert('click');
}
return true;
});
bindEvent(); //只在第一次时绑定
bindEvent();
bindEvent();
策略模式
- 定义并封装一系列的算法,并且使他们可以互相替换
- 一个基于策略模式的程序至少由两部分组成:
- 策略类:封装了具体的算法,并负责具体的计算过程;
- 环境类:接受请求后委托给某个策略类;
模拟策略实现
/**
* 计算奖金
*/
//策略类
var performancsA = function () {}
performancsA.prototype.calculate = function(salary) {
return salary * 3;
};
var performancsB = function () {}
performancsB.prototype.calculate = function(salary) {
return salary * 4;
};
//环境类
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.getBouns = function() {
return this.strategy.calculate(this.salary);
};
var bouns = new Bonus;
bouns.setSalary(10000);
bouns.setStrategy(new performancsA);
bouns.getBouns();//30000;
bouns.setStrategy(new performancsB);
bouns.getBouns();//40000;
JS中的策略模式
var strategies = {
'A': function (salary) {
return salary * 3;
},
'B': function (salary) {
return salary * 4;
}
};
var calculateBonus = function(level, salary) {
return strategies[level](salary);
};
calculateBonus('A', 10000);
calculateBonus('B', 10000);
实现缓动动画
//缓动算法
var tween = {
linear: function(t, b, c, d) { //已消耗的时间,原始位置,目标位置,持续总时间
return c * t / d + b;
},
easeIn: function(t, b, c, d) {
return c * (t /= d) * t + b;
},
strongEaseIn: function(t, b ,c ,d) {
return c * (t /= d) * t * t * t * t + b;
},
strongEaseOut: function(t, b, c, d) {
return c * ((t = t / d - 1) * t * t * t * t * t + 1) + b;
},
sineaseIn: function(t, b, c, d) {
return c * (t /= d) * t * t + b;
},
sineaseOut: function(t, b ,c ,d) {
return c * ((t = t /d - 1) * t * t + 1) + b;
},
};
var Animate = function (elem) {
this.elem = elem;
this.startTime = 0;
this.startPos = 0;
this.endPos = 0;
this.properrtName = null;
this.easing = null;
this.duration = null;
};
Animate.prototype.start = function (properrtName, endPos, duration, easing) {
var self = this;
self.startTime = +new Date;
self.startPos = self.elem.getBoundingClientRect()[properrtName];
self.properrtName = properrtName;
self.endPos = endPos;
self.duration = duration;
self.easing = tween[easing];
var timeId = setInterval(function() {
if(self.step() === false)
clearInterval(timeId);
}, 20);
};
Animate.prototype.step = function() {
var t = +new Date;
if(t >= this.startTime + this.duration) {
this.update(this.endPos);
return false;
}
var pos = this.easing(t - this.startTime, this.startPos, this.endPos - this.startPos, this.duration);
this.update(pos);
};
Animate.prototype.update = function(pos) {
this.elem.style[this.properrtName] = pos + 'px';
}
var div = document.getElementById('div');
var animate = new Animate(div);
animate.start('left', 500, 1000, 'sineaseIn');
实现表单验证
var InputStrategy = function () {
var strategy = {
notNull: function (value) {
return /s+/.test(value) ? '请输入内容' : '';
},
number: function (value) {
return /^[0-9]+(.[0-9]+)?$/.test(value) ? '' : '请输入数字';
},
phone: function (value) {
return /^d{3}-d{8}$|^d{4}-d{7}$/.test(value) ? '' : '请输入数字';
}
}
return {
check: function (type, value) {
value = value.replace(/^s+|s+$/g, '');
return strategy[type] ? strategy[type](value) : '没有改类型的检验方法'
},
//添加策略
addStrategy: function (type, fn) {
strategy[type] = fn;
}
}
}();
//扩展
InputStrategy.addStrategy('nickname', function (value) {
console.log(value);
return /^[a-zA-Z]w{3,7}$/.test(value) ? '' : '请输入4-8位昵称'
});
console.log(InputStrategy.check('nickname', 'aaaa'));
优点
- 利用组合、委托、多态等,有效避免多重条件选择
- 对开放-封闭原则的支持
- 重用性高
- 组合和委托方式来替代继承
- JS中,由于函数是一等公民,策略类常常被函数替代而隐性使用策略模式;
与状态模式
- 都是在内部封装一个对象,然后通过返回的接口对象实现对象内部对象的调用;
- 策略模式不需要管理状态,状态之间没有依赖关系,策略之间可以互相替换;在策略对象内部保存的是相互独立的算法;