首页 > 代码库 > js模式与设计模式
js模式与设计模式
优点:
1.封装私有变量---对于上来就初始化且不让修改的,对于只需执行一次的工作
2.变量用于自调用函数不污染全局变量,封装模块提供一个作用域沙箱
用于
初始化分支
var util = {
addListener:function(ele,type,handle){
if (typeof window.addEventListener ===‘function‘) {
ele.addEventListener(type,handle,false);
}else if (typeof document.attachEvent === ‘function‘) {
ele.attachEvent(‘on‘+type,handle);
}else{
ele[‘on‘+type]=handle;
}
}
}
上面这段代码要每次都会检测效率低下
整个生命周期内只需检测一次所以优化
var util = {
addListener:null,
removeListener:null
}
if (typeof window.addEventListener ===‘function‘) {
util.addListener=function(ele,type,fn){
ele.addEventListener(type,fn,false);
}else if (typeof document.attachEvent === ‘function‘) {
util.addListener = function(ele,type,fn){
ele.attachEvent(‘on‘+type,fn);
};
}else{
util.addListener=function(ele,type,fn){
ele[‘on‘+type] = fn;
};
}
};
探测浏览器
函数属性----备忘模式
缓存结果
var myFunc = function(param){
if (!myFunc.cache[param]) {
var result = {};
myFunc.cache[param] = result;
};
return myFunc.cache[param];
};
myFunc.cache = {};
优化---可以传复杂参数
var myFunc = function(){
var cachekey = JSON.stringify(Array.prototype.slice.call(arguments)),result;
if (!myFunc.cache[cachekey]) {
result = {};
var result = {};
myFunc.cache[cachekey] = result;
};
return myFunc.cache[cachekey];
};
myFunc.cache = {};
命名空间
var MYAPP = MYAPP||{};
MYAPP.namespace = function(ns_string){
var parts = ns_string.split("."),
parent = MYAPP,
i;
if (parts[0] ==="MYAPP") {
parts = parts.slice(1);
};
for (var i = 0,len = parts.length; i <len; i++) {
//如果不存在就创建一个属性
if (typeof parent[parts[i]]===‘undefined‘) {
parent[parts[i]] ={};
};
parent=parent[parts[i]];
};
return parent;
}
声明依赖:
优点
1.显式声明依赖向代码用户表明他们需要的脚本已加载进页面
2.在函数的顶部声明很容易发现并解析依赖
3.解析局部变量快于全局变量
var myFunc = function(){
var event =YAHOO.util.Event,
dom = YAHOO.util.Dom;
}
私有变量:---即局部变量
特权方法:---可以访问私有成员的公有方法(对象字面量级私有、原型和私有、揭示模式)
//对象字面量及私有性
var myobj;
(function(){
varname="xiaoyu";
myobj = {
getName:function(){
returnname;
}
};
}());
原型和私有
function Gadget(){
var name=‘iPod‘;
this.getName =function(){
returnname;
};
}
Gadget.prototype = (function(){
var browser ="mobile webkit";
return {
getBrowser:function(){
returnbrowser;
}
}
}());
var toy = new Gadget();
console.log(toy.getName());//特权“own”方法
console.log(toy.getBrowser());//特权原型方法
揭示模式
var myarray =(function(){
var astr = "[objectArray]",
toString = Object.prototype.toString;
function isArray(a){
return tiString.call(a)===astr;
}
functionindexOf(haystack,needle){
vari =0,max = haystack.length;
for(;i<max;i++){
if(haystack[i] === needle) {
returni;
};
}
return-1;
}
myarray = {
isArray:isArray,
indexOf:indexOf,
inArray:indexOf
}
});
//模块模式
// 命名空间
// 即时函数
// 私有和特权成员
// 声明依赖
MYAPP.namespace(‘MYAPP.util.array‘);
MYAPP.util.array = (function(){
// 依赖
var uobj =MYAPP.util.object,
ulang = MYAPP.prototype.lang,
// 私有属性
array_string = "[object Array]",
ops = Object.prototype.toString;
// 私有方法
// 可选一次性初始化过程
// 公有API
return{
inArray:function(needle,haystack){
for(vari=0,max=haystack.length;i<max;i+=1){
if(haystack[i]===needle) {
returntrue;
};
}
},
isArray:function(a){
returnops.call(a) === array_string;
}
}
})
// 创建构造函数的模块
MYAPP.namespace(‘MYAPP.util.Array‘);
MYAPP.util.Array = (function(){
var uobj = MYAPP.util.object,
ulang = MYAPP.prototype.lang,
// 私有属性
Constr;
// ....
Constr = function(o){
this.ele =this.toArray(o);
};
Constr.prototype ={
constructor:MYAPP.util.Array,
version:"2.0",
toArray:function(obj){
for(vari=0,a=[].len=obj.length;i<len;i+=1){
a[i]= obj[i];
}
returna;
}
return Constr;
}
});
// 沙箱模式
function Sandox(){
var args =Array.prototype.slice.call(arguments),
callback = args.pop(),
modules = (args[0]&& typeof args[0]===‘string‘)?args:args[0],i;
// 确保该函数作为构造函数调用
if (!(this instanceof Sandox)) {
return newSandox(modules,callback);
}
this.a = 1;
this.b=2;
// 向该核心this添加模块
if (!modules||modules==="*") {
modules = [];
for(i inSandox.modules){
if(Sandox.modules.hasOwnProperty) {
modules.push(i);
};
}
};
// 初始化需要加载的模块
for(i=0;i<modules.length;i+=1){
Sandox.modules[modules[i]](this);
}
callback(this);
}
Sandox.modules = {};
Sandox.modules.dom = function(box){
box.getElement = function(){};
box.getStyle = function(){};
box.foo = "bar";
}
// Sandox.modules.event =function(){.....}
// Sandox.modules.ajax = function(){}
Sandox(‘ajax‘,‘dom‘,function(box){
// ....
})
链模式
优点
1.节省输入一些字符,是代码简洁
2.可以帮助您考虑翻个函数。穿件更加简短具有特定功能的函数提高代码的可维护性
缺点:
代码难以调试
方法:当代吗没有明显和有意义的返回值时可以返回this
method方法
// method
Function.prototype.method= function(name,implementation){
if(typeofFunction.prototype.method!=="function"){
Function.prototype.method= function(name,implementation){
this.prototype[name]= implementation;
returnthis;
}
}
}
var Person = function(name){
this.name =name;
}.method(‘getName‘,function(){
returnthis.name;
}).method(‘setName‘,function(){
return this;
})
单体模式({}就是一个单体)
使用new操作符穿件多个对象时,应尽获得指向完全相同的对象的新指针
1静态属性缓存
function Universe(){
if(typeof Universe.instance ==="object"){
return Universe.instance;
}
this.start_time = 0;
this.bang = "Big";
Universe.instance = this;
// return this;
}
var uni = new Universe();
var uni2 = new Universe();
uni===uni2;
//缺点该实例属性是公开的
闭包中的实例 ---缺点是带来了额外的开销
function Universe(){
this.start_time = 0;
this.bang = "Big";
var instance = this;
Universe = function (){
return instance;
}
// return this;
}
Universe.prototype.nothing =true;
var uni = new Universe();
Universe.prototype.everything=true;
var uni2 = new Universe();
Universe.prototype.something =true;
uni===uni2;
uni===uni2;
true
uni.nothing
true
uni2.nothing
true
uni.everything
undefined
uni.something
undefined
注释:第一次调用想往常一样返回this以后Universe被重写为
function (){
return instance;
}一直引用着instance
缺点当第一次调用后为原型添加属性方法不会被添加到实例上
改进
function Universe(){
// 缓存实例
var instance;
// 保留原型属性 此时的Universe是重写或的构造函数this是重写之前的
Universe = function Universe(){
return instance;
}
// 保留原型属性
Universe.prototype = this;
instance = new Universe();
instance.constructor = Universe;
instance.start_time = 0;
instance.bang = "big";
return instance;
}
方法二
即时函数
var Universe;
(function(){
var instance;
Universe = function Universe(){
if(instance){
return instance;
}
instance = this;
this.start_time=0;
this.bang = "big";
};
}());
工厂模式
找到要穿件的构造函数即可return相应对象
function CarMaker(){}
CarMaker.prototype.dirve = function(){
return "Vroom,I have "+this.doors+" doors";
};
CarMaker.factory = function(type){
var constr = type,newcar;
if(typeof CarMaker[constr] !== "function"){
throw{
name:"Error",
message:constr + " doesn‘t exist"
};
}
if(typeof CarMaker[constr].prototype.dirve !== "function"){
CarMaker[constr].prototype = new CarMaker();
}
newcar = new CarMaker[constr]();
return newcar;
};
CarMaker.Compact = function(){
this.doors = 4;
}
CarMaker.Convertible = function(){
this.doors = 2;
}
CarMaker.SUV = function(){
this.doors = 24;
}
迭代器模式
var agg = (function(){
var index =0,data=http://www.mamicode.com/[1,2,3,4,5],length=data.length;
return{
next:function(){
var element;
if(!this.hasNext()){
return null;
}
element = data[index];
index+=2;
return element;
},
hasNext:function(){
return index < length;
},
rewind:function(){
index = 0;
},
current:function(){
return data[index];
}
}
}());
// 装饰者模式
function Sale(price){
this.price = price ||100;
}
Sale.prototype.getPrice = function(){
return this.price;
}
Sale.decorators ={};
Sale.decorators.fedtax = {
getPrice:function(){
var price = this.uber.getPrice();
price += price*5/100;
return price;
}
};
Sale.decorators.quebec = {
getPrice:function(){
var price = this.uber.getPrice();
price += price*7.5/100;
return price;
}
};
Sale.decorators.money = {
getPrice:function(){
return "$"+this.uber.getPrice().toFixed(2);
}
};
Sale.decorators.cdn = {
getPrice:function(){
return "CDN$"+this.uber.getPrice().toFixed(2);
}
};
Sale.prototype.decorators = function(decorator){
var F = function(){},
overrides = this.constructor.decorators[decorator]; //this.constructor---Sale.prototype.constructor指向的是Sale
i,newObj;
F.prototype = this;
newObj = new F();
newObj.uber = F.prototype;
for(i in overrides){
if(overrides.hasOwnProperty(i)){
newObj[i] = overrides[i];
}
}
return newObj;
}
// 使用列表实现
function Sale(price){
this.price = price ||100;
this.decorators_list =[];
}
Sale.prototype.getPrice = function(){
return this.price;
}
Sale.decorators ={};
Sale.decorators.fedtax = {
getPrice:function(price){
price += price*5/100;
return price;
}
};
Sale.decorators.quebec = {
getPrice:function(price){
price += price*7.5/100;
return price;
}
};
Sale.decorators.money = {
getPrice:function(price){
return "$"+price.toFixed(2);
}
};
Sale.decorators.cdn = {
getPrice:function(price){
return "CDN$"+price.toFixed(2);
}
};
Sale.prototype.decorators = function(decorator){
this.decorators_list.push(decorator);
};
Sale.prototype.getPrice = function(){
var price = this.price, //
this
Sale {price: 200, decorators_list: Array[2], decorators: function, getPrice: function}this指向的是构造函数
i,max = this.decorators_list.length,
name;
for(i = 0;i<max;i+=1){
name = this.decorators_list[i];
price = Sale.decorators[name].getPrice(price);
}
return price;
}
策略这模式
支持运行时选择算法代码客户端可以使用同一个接口工作单她根据客户正在试图执行任务的上下文荀泽处理特定人去的算法
var data = http://www.mamicode.com/{
first_name:"super",
last_name:"Man",
age:"unknown",
username:"LS"
}
var validator = {
types:{},
messages:[],
config:{},
validate:function(data){
var i,msg,type,checker,result_ok;
this.messages =[];
for(i in data){
if(data.hasOwnProperty(i)){
type = this.config[i];
checker = this.types[type];
if(!type){
continue;
}
if(!checker){
throw{
name:"ValidationError",
message:"no handle to validate type"+type
};
}
result_ok = checker.validate(data[i]);
if(!result_ok){
msg = "Invalid value for *"+i+"*,"+checker.instructions;
this.messages.push(msg);
}
}
}
return this.hasErrors();
},
hasErrors:function(){
return this.messages.length !== 0;
}
}
validator.config = {
first_name:‘isNonEmpty‘,
age:‘isNumber‘,
username:‘isAlphaNum‘
}
validator.types.isNonEmpty ={
validate:function(value){
return value!=="";
},
instructions:"the value cannot be empty"
}
validator.types.isNumber ={
validate:function(value){
return !isNaN(value);
},
instructions:"the value can only be a valid number,"
}
validator.types.isAlphaNum ={
validate:function(value){
return !/[^a-z0-9]/i.test(value);
},
instructions:"the value can only be contain characters and numbers,no special aymbols"
}
validator.validate(data);
if (validator.hasErrors()) {
console.log(validator.messages.join("\n"));
};
Invalid value for *age*,the value can only be a valid number,
外观者模式
为对象提供一个可供选择的接口
(有时两个或多个方法可能普遍的被一起调用,这时川建一个方法一包装重复的方法调用非常有意义)
浏览器事件--stopPropagation() preventDefault()
var myevent={
stop:function(e){
if(typeof e.preventDefault ==="function"){
e.preventDefault();
}
if(typeof e.stopPropagation==="function"){
e.stopPropagation();
}
if(typeof e.returnValue http://www.mamicode.com/==="boolean"){
e.returnValue = http://www.mamicode.com/false;
}
if(typeof e.cancelBubble ==="boolean"){
e.cancelBubble = false;
}
}
}
var EventUtil = {
addHandler: function(element, type, handler){
if (element.addEventListener){
element.addEventListener(type, handler, false);
} else if (element.attachEvent){
element.attachEvent("on" + type, handler);
} else {
element["on" + type] = handler;
}
},
getButton: function(event){
if (document.implementation.hasFeature("MouseEvents", "2.0")){
return event.button;
} else {
switch(event.button){
case 0:
case 1:
case 3:
case 5:
case 7:
return 0;
case 2:
case 6:
return 2;
case 4: return 1;
}
}
},
getCharCode: function(event){
if (typeof event.charCode == "number"){
return event.charCode;
} else {
return event.keyCode;
}
},
getClipboardText: function(event){
var clipboardData =http://www.mamicode.com/ (event.clipboardData || window.clipboardData);
return clipboardData.getData("text");
},
getEvent: function(event){
return event ? event : window.event;
},
getRelatedTarget: function(event){
if (event.relatedTarget){
return event.relatedTarget;
} else if (event.toElement){
return event.toElement;
} else if (event.fromElement){
return event.fromElement;
} else {
return null;
}
},
getTarget: function(event){
return event.target || event.srcElement;
},
getWheelDelta: function(event){
if (event.wheelDelta){
return (client.engine.opera && client.engine.opera < 9.5 ? -event.wheelDelta : event.wheelDelta);
} else {
return -event.detail * 40;
}
},
preventDefault: function(event){
if (event.preventDefault){
event.preventDefault();
} else {
event.returnValue = http://www.mamicode.com/false;
}
},
removeHandler: function(element, type, handler){
if (element.removeEventListener){
element.removeEventListener(type, handler, false);
} else if (element.detachEvent){
element.detachEvent("on" + type, handler);
} else {
element["on" + type] = null;
}
},
setClipboardText: function(event, value){
if (event.clipboardData){
event.clipboardData.setData("text/plain", value);
} else if (window.clipboardData){
window.clipboardData.setData("text", value);
}
},
stopPropagation: function(event){
if (event.stopPropagation){
event.stopPropagation();
} else {
event.cancelBubble = true;
}
}
};
代理模式----以一个对象充当另一个对象的接口
与外观模式的区别
外观模式是拥有合并了多个方法调用的遍历方法代理则是介于对象客户端与对象本身之间并且对该对象的访问进行保护
优点:使用代理可以合并和减少到服务器的往返次数
典型的是延迟初始化
事件代理事件处理程序
进一步优化----缓存代理(缓存请求的结果cache)
中介者:在多对象之间回旋
观察者模式-------------自定义事件订阅/发布模式
所有浏览器事件是该模式(鼠标悬停,按键等事件)例子
这种模式不是一个对象调用另一个对象的方法而是一个对象的特定活动并在状态改变后获得通知
订阅者为观察者
js模式与设计模式