由 OO 继承来谈谈 javascript 继承
在大多数面向对象语言中,基本上的都支持继承,首先来宽泛的谈谈大多数 OO 语言的继承方式,之后具体到 javascript 来看看其继承有什么不同之处。
1. 实现继承:实现继承是指派生类(子类)继承了基类(父类)的所有属性和方法,并且有且只有一个基类。
优点是可以直接使用基类的所有属性和方法,缺点不言而喻,基类的一些不必要的方法也会被子类所继承。
比如:基类定义了果树类,里面有开花,结果等方法。派生类继承基类,但如果派生类的中的果树不会开花,只会结果(如:无花果),那么开花对子类就没用,但子类确实继承了基类开花的方法。
在设计模式中,我们更多强调的是面向接口的继承。上面的例子中,果树有两个接口,一个是开花,一个是结果。如果我的果树只能结果,不会开花的话,那么只要我的果树实现结果的接口就行了。与此同时不会把开花带入到我的派生类(子类)中。
2. 接口继承:派生类继承了接口的方法签名,它不同于实现继承的是,接口继承允许多继承,同时派生类只继承了方法签名而没有方法实现。具体的实现必须在派生类中完成。这种继承又称为“接口实现”。
谈完了 OO 语言继承的分类,下面对比上述两种方式来看看 javascript 是怎么来完成它独有的继承的。
先看第二点——接口继承,接口继承要求派生类继承基类的方法签名。
方法签名:返回值类型+方法名+参数列表
而在 javascript 中,任何的函数,方法,究其本质都会转变成变量来解析,如下:
//定义式function a(){ alert("pluto");}//变量式var a = function(){ alert("Pluto");}
function Fruit(){ this.fruit = true;}Fruit.prototype.isFruit = function(){ return this.fruit;}function NotFruit(){ this.notFruit = false;}NotFruit.prototype = new Fruit();//将 Fruit()的实例赋值给另外一个构造函数 (NotFruit) 的原型对象 (NotFruit.prototype)NotFruit.prototype.isNotFruit = function(){ return this.notFruit;}var dog = new NotFruit(); // 创建派生类(子类)的实例 dogalert(dog.isFruit()); // 输出 truealert(dog.isNotFruit()); // 输出 falsealert(dog.notFoundFruit()); // 报错 dog.notFoundFruit is not a function