程序的开发离不开代码的复用,通过代码复用可以减少开发和维护成本,在谈及代码复用的时候,会首先想到继承性,但继承并不是解决代码复用的唯一方式,还有其他的复用模式比如对象组合。本节将会讲解多种继承模式以实现代码复用。
- 继承复用-默认模式
- 继承复用-apply函数
- 继承复用-临时构造
继承复用之默认模式:
每个javascript对象都和另一个对象 相关联,而这个对象就是原型(prototype),而原型又可以链接到其他原型行程原型链,如果当前对象不存在类似方法则会沿原型链查找,直到查找为止。继承的默认模式即通过这种原型链的特性实现的。
Person类为基类定义了一些属性和方法
/** * person 基类 */ var Person = function () { this.name = ""; this.age = 0; this.sex = ""; this.say = function () { return "my name is" + this.name; } } Person.prototype.sayHello = function () { return "Hello"; }
定义一个空的子函数对象
/** * 原型继承 */ var Engineer1 = function () { }
将子对象的原型链中加入父类和父类原型
Engineer1.prototype = new Person(); var enginneer1 = new Engineer1(); enginneer1.name = ‘stephen‘; console.log(enginneer1.say());
此类继承实现缺点:
不能传递构造的参数:假设person基类中可以接受构造传参,而继承的子类想通过父类构造传递参数则是不可行的。
继承复用-apply函数
apply函数定义:用于调用当前函数functionObject
,并可同时使用指定对象thisObj
作为本次函数执行时函数内部的this
指针引用。通俗的讲,就是将当前函数对象的成员复制到this所引用的函数对象中去。
可以在子类构造中通过apply方法将父类的成员复制到子类中,而且可以通过apply传递参数,而不是绑定原型链,
var Engineer2 = function () { Person.apply(this); }
相反由于不是绑定原型链因此如果在父类原型中的方法是不能被继承的 ,如下代码所示
Person.prototype.sayHello = function () { return "Hello"; }
使用示例
var enginner2 = new Engineer2(); enginner2.name = ‘adam‘; console.log(enginner2.say());
继承复用-临时构造
上面两种方法各有优劣,但都不完美,默认继承不能传递构造的参数,而通过Apply()函数的构造绑定又不能继承父类原型链的方法,而且有时基类有私有的方法不想被子类继承,以上两种都不能做到。而临时构造函数的方法能得到一个比较完美的解决方案。
首先生成一个临时函数对象,通过原型链共享将临时函数对象的原型链指定为父类原型链(注意这里不是绑定哦),接着将子类的原型链绑定上临时函数的原型链。
var temp = function (){}; temp.prototype = Person.prototype; Engineer1.prototype = new temp(); var enginner3 = new Engineer1(); enginner3.name = "stphen"; console.log(enginner3.say());
通过上面代码的处理,子对象拥有了临时函数的原型链,却没有继承父类在函数中定义的成员,这样如果想要定义私有的方法则可以在函数定义中,如果想定义可继承方法可在函数prototype中,从而比较完美的解决继承。
小结:
在javascript中实现继承有许多方法,在本节中讲解了三种主要的方法,每种方法继承都有各自的优势和缺点,可以在开发项目时约定使用某一种方式,当然除了继承外还可以使用apply借用某一个方法从而达到复用的目的,毕竟为了使用某一个方法而建立长长的原型链并不是一种可取的方式。
参考内容
《javascript 模式》 stoyan stefanov