设计模式
一、类继承它描绘了被创建对象的属性及特征。使用new关键字调用构造函数可以创建类的实例
基于原型的面向对象设计方法总共有三种
1、拼接继承: 是直接从一个对象拷贝属性到另一个对象的模式。被拷贝的原型通常被称为mixins。ES6为这个模式提供了一个方便的工具Object.assign()。在ES6之前,一般使用Underscore/Lodash提供的.extend(),或者 jQuery 中的$.extend(), 来实现。
2、原型代理:JavaScript中,一个对象可能包含一个指向原型的引用,该原型被称为代理。如果某个属性不存在于当前对象中,就会查找其代理原型。代理原型本身也会有自己的代理原型。这样就形成了一条原型链,沿着代理链向上查找,直到找到该属性,或者找到根代理Object.prototype为止。原型就是这样,通过使用new关键字来创建实例以及Constructor.prototype前后勾连成一条继承链。当然,也可以使用Object.create()来达到同样的目的,或者把它和拼接继承混用,从而可以把多个原型精简为单一代理,也可以做到在对象实例创建后继续扩展。
3、函数继承:在JavaScript中,任何函数都可以用来创建对象。如果一个函数既不是构造函数,也不是 class,它就被称为工厂函数。函数继承的工作原理是:由工厂函数创建对象,并向该对象直接添加属性,借此来扩展对象(使用拼接继承)。
类式继承:
//声明父类 function SuperClass(){ this.superValue = true; } //为父类添加共有方法 SuperClass.prototype.getSuperValue = function(){ return this.superValue; } //声明子类 SubClass.prototype = new SuperClass(); //为子类添加共有方法 SubClass.prototype.getSubClassValue = function(){ return this.subValue; }
构造函数式继承
//声明父类 function SuperClass(id){ this.books = ['js','css','html']; this.id = id; } //父类声明原型方法 SuperClass.prototype.showBooks = function(){ console.log(this.books); } //声明子类 function SubClass(id){ //继承父类 SuperClass.apply(this,id); }
多继承
var extend = function(target, source){ for(var prototype in source){ target[prototype] = source[prototype]; } return target; }
call,apply作用一样,只是参数形式不同。
1)指定this指向 func.call(this)
2)Function.prototype.bind大部分浏览器支持,指定内部指向。
//简化版 Function.prototype.bind = function(context){ var self = this; //保持原函数 return function(){ //返回新函数 return self.apply(context,arguments); //执行新函数,把之前传入的context作为新函数的this } } var obj = {this.name = 'seven'} var func = function(){ console.log(this.name); }.bind(obj); func();//输出seven
//借用构造函数 var A = function(name){ this.name = name; }; var B = function(){ A.apply(this,arguments); }; B.prototype.getName = function(){ return this.name; }; var b = new B('seven'); console.log(b.getName()) //输出seven
二、模式是经过了大量实际项目经验的优秀解决方案,javascript的函数既可以作为普通函数被调用,也可以作为构造器使用。
1、单例模式:保证一个类只有一个实例
var singleton = function(name){ this.name = name; }; singleton.prototype.getName = function(){ console.log(this.name); } singleton.getInstance = (function(){ var instance = null; return function(name){ if(!instance){ instance = new singleton(name); } return instance; } })();
使用闭包封装私有变量
var user = (function(){ var _name = 'seven', _age = 25; return { getUserInfo: function(){ return _name + '_' + _age; } } })();
单例逻辑抽离
var getSingle = function(fn){ var result; return function(){ return result || (result = fn.apply(this,arguments)); } }
2、策略模式:定义一系列算法,把它们一个个封装起来,并且使它们可以相互替换。适合类似表单验证等情况,减少if-else
var strategies = { 'S': function(salary){ return salary * 4; }, 'A': function(salary){ return salary * 3; }, 'B': function(salary){ return salary * 2; } };
3、代理模式:为对象提供一个代用品或占位符,以便控制它的访问
图片懒加载:
var myImage = (function(){ var imgNode = document.creatElement('img'); document.body.appendChild(imgNode); return { setSrc : function(src){ imgNode.src = src; } } })() var proxyImage = (function(){ var img = new Image; img.onload = function(){ myImage.setSrc(this.src); } return { setSrc: function(src){ myImage.setSrc('file://loading.gif'); img.src = src; } } })(); proxyImage.setSrc('http://pic.png');
计算乘积
var mult = function(){ var a = 1; for(var i = 0, l = arguments.length; i < l; i++){ a = a * arguments[i]; } return a; }; var plus = function(){ var a = 1; for(var i = 0, l = arguments.length; i < l; i++){ a = a + arguments[i]; } return a; };
创建缓存代理的工厂
var createProxyFactory = function(fn){ var cache = {}; return function(){ var args = Array.prototype.join.call(arguments,','); if(args in cache){ return cache[args]; //缓存计算结果 } return cache[args] = fn.apply(this,arguments); } }; var proxyMult = createProxyFactory(mult), proxyPlus = createProxyFactory(plus); console.log(proxyMult(1,2,3,4)); //24 console.log(proxyMult(1,2,3,4)); //24 console.log(proxyPlus(1,2,3,4)); //10 console.log(proxyPlus(1,2,3,4)); //10
4、迭代器模式:提供一种方法可以顺序访问一个聚合对象中各个元素,而不需要暴露该对象的内部表示
5、发布-订阅模式(观察者模式):一种一对多的关系,当一个对象状态发生改变时,所有依赖它的对象都将得到通知
缺点:模块间使用太多发布-订阅模式通信,模块与模块之间的联系被隐藏到背后,会搞不清消息来自哪个模块,或者消息流向哪个模块。给维护带来麻烦。同时消息订阅后但最后都未发生,订阅者会始终存在于内存中
6、命令模式:执行某些特定事情的指令
7、模版方法模式:基于继承的设计模式
8、享原模式:用于性能优化的模式,用共享技术有效支持大量细粒度的对象
9、职责链模式:将对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理完它为止。
优:解耦请求发送者何N个接收者之间的关系。
缺:某次请求中大部分节点都没有起到实质作用,从性能考虑尽量避免过长职责链。
10、中介者模式:解除紧耦和关系,增加一个中介者对象,当一个对象改变时只需要通知中介者对象即可。
缺点:系统增加中介者对象,使复杂度转移到了中介者对象中。
11、装饰者模式:动态的给某个对象添加一些额外的职责,而不会影响从这个类中派生的其它对象
继承:父类子类耦合性强,且父类对子类可见,破坏了封装性。
12、状态模式