JavaScript继承的几种方法比较
来源:互联网 发布:淘宝运营一般工资多少 编辑:程序博客网 时间:2024/05/23 20:59
许多OO语言都支持两种继承方式:接口继承和实现继承。接口继承只继承方法签名,而实现继承则继承实际的方法。
由于在ECMAScript中,某些函数没有函数名,即匿名函数,因此ECMAScript只支持实现继承。并且主要是通过原型链来实现继承的。
一、原型链
实现原型链继承的基本模式:
function SuperType(){ this.property = true;}SuperType.prototype.getSuperValue = function(){ return this.property;};function SubType(){ this.subproperty = false;}//继承了SuperTypeSubType.prototype = new SuperType();SubType.prototype.getSubValue = function(){ return this.subproperty;};var instance = new SubType();alert(instance.getSuperValue()); //truealert(instance.getSubValue()); //false
以上代码定义了两个类型:SuperType和SubType。其中创建了SuperType的实例,并将该实例赋值给SubType.prototype,因此SubType继承了SuperType。在继承之后,给SubType.prototype添加了一个新方法getSubValue() 。
我们没有使用SubType默认提供的原型,而是给它换了一个新原型;这个新原型就是SuperType的实例,因此,新原型不仅具有作为一个SuperType的实例所拥有的全部属性和方法,而且其内部还有一个指针,指向了SuperType的原型。
最终结果:instance指向SubType的原型,SubType的原型又指向了SuperType的原型。getSuperValue()方法仍然在SuperType.prototype中,但property位于SubType中。这是因为property是一个实例属性,而getSuperValue()则是一个原型方法,既然SubType.prototype现在是SuperType的实例,那么property当然就位于该实例中了。
原型链的问题:
function SuperType(){ this.colors = ["red","blue","green"];}function SubType(){}//继承了SuperTypeSubType.prototype = new SuperType();var instance1 = new SubType();instance1.colors.push("black");alert(instance1.colors); //"red,blue,green,black"var instance2 = new SubType();alert(instance2.colors); //"red,blue,green,black"
1、含引用类型值的原型属性会被所有实例共享:
以上代码中,SuperType构造函数定义了一个colors属性,当SubType通过原型链继承了SuperType之后,SubType.prototype就变成了SuperType的一个实例,因此它也拥有了一个它自己的colors属性——就跟专门创建了一个SubType.prototype.colors属性也一样。结果是SubType的所有实例都会共享这一个colors属性。
简单来说,SuperType通过构造函数创建的属性本来不会被SuperType的实例共享,但继承后,这些属性成为SubType的原型属性,被SubType的所有实例共享。(通过构造函数定义的属性不会被实例共享,通过原型定义的属性会被实例共享)
可参考http://blog.csdn.net/weixin_39480464/article/details/78294552
2、在创建子类型的实例时,不能向超类型的构造函数中传递参数。
二、借用构造函数实现继承(伪造对象或经典继承)
通过使用apply()和call()方法在新创建的对象上执行构造函数。
function SuperType(){ this.colors = ["red","blue","green"];}function SubType(){ //继承了SuperType SuperType.call(this);}var instance1 = new SubType();instance1.colors.push("black");alert(instance1.colors); //"red,blue,green,black"var instance2 = new SubType();alert(instance2.colors); //"red,blue,green"
这一句代码“SuperType.call(this);”借调了超类型的构造函数。通过call()方法或apply()方法,在未来将要新创建的SubType实例的环境调用了SuperType构造函数。这样,SubType的每个实例都会有自己的colors属性的副本。
借用构造函数的问题:
如果仅仅是借用构造函数,那么也将无法避免构造函数模式存在的问题——方法都在构造函数中定义,因此函数复用就无从谈起了。而且,在超类型的原型中定义的方法,对子类型而言也是不可见的,结果所有类型都只能使用构造函数模式。
三、组合继承(伪经典继承)
组合继承将原型链和借用构造函数的技术组合到一块,既避免了构造函数不能复用函数的问题,又避免了实例共享原型链属性的问题。其背后的思路是使用原型链实现对原型属性和方法的继承,而通过借用构造函数来实现对实例属性的继承。这样,既通过在原型上定义方法实现了函数复用,又能够保证每个实例都有它自己的属性。
function SuperType(name){ this.name = name; this.colors = ["red", "blue", "green"];}SuperType.prototype.sayName = function(){ alert(this.name); };function SubType(name, age){ //继承属性 SuperType.call(this, name); this.age = age;}//继承方法SubType.prototype = new SuperType();SubType.prototype.constructor = SubType;SubType.prototype.sayAge = function(){ alert(this.age);};var instance1 = new SubType("Nicholas", 29);instance1.colors.push("black");alert(instance1.colors); //"red,blue,green,black"instance1.sayName(); //"Nicholas";instance1.sayAge(); //29var instance2 = new SubType("Greg", 27);alert(instance2.colors); //"red,blue,green"instance2.sayName(); //"Greg";instance2.sayAge(); //27
组合继承避免了原型链和借用构造函数的缺陷,融合了它们的优点,成为 JavaScript 中最常用的继承模式。
组合继承的缺点:
组合继承最大的问题就是无论什么情况下,都会调用两次超类型构造函数:一次是在创建子类型原型的时候,另一次是在子类型构造函数内部。
function SuperType(name){ this.name = name; this.colors = ["red", "blue", "green"];}SuperType.prototype.sayName = function(){ alert(this.name);};function SubType(name, age){ SuperType.call(this, name); //第二次调用SuperType() this.age = age;}SubType.prototype = new SuperType(); //第一次调用 SuperType()SubType.prototype.constructor = SubType;SubType.prototype.sayAge = function(){ alert(this.age);};
四、寄生组合式继承
function SuperType(name){ this.name = name; this.colors = ["red", "blue", "green"];}SuperType.prototype.sayName = function(){ alert(this.name);};function SubType(name, age){ SuperType.call(this, name); this.age = age;}inheritPrototype(SubType, SuperType);SubType.prototype.sayAge = function(){ alert(this.age);};
这个例子的高效率体现在它只调用了一次 SuperType 构造函数,并且因此避免了在 SubType.prototype 上面创建不必要的、多余的属性。与此同时,原型链还能保持不变;因此,还能够正常使用instanceof 和 isPrototypeOf()。开发人员普遍认为寄生组合式继承是引用类型最理想的继承范式。
- JavaScript继承的几种方法比较
- javascript 继承类的几种方法
- javascript的几种继承方法
- JavaScript继承实现的几种方法
- javascript的几种继承方法
- JavaScript中的继承以及实现继承的几种方法
- javascript中类继承的几中的几种方法
- Javascript中的几种继承方式比较
- Javascript中的几种继承方式比较
- Javascript中的几种继承方式比较
- JavaScript中的关于继承的几种方法
- 几种继承模式的比较
- javascript 对象继承的几种方式
- JavaScript继承的几种方式解析
- javascript 继承的几种方式
- JavaScript继承的几种方式
- javascript 实现继承的几种方式
- javascript的几种继承方式
- 其他题目---正数数组的最小不可组成和
- Kotlin类和对象 (七)--- 密封类(sealed class)
- Java
- 查询表信息
- 关于Python函数中self参数使用介绍
- JavaScript继承的几种方法比较
- 优化:深度神经网络Tricks【笔记】
- 关于measure
- MySQL数据库的高可用方案
- ECharts_01_柱形图
- Python初级教程:入门详解
- Java Security Architecture--Java安全体系技术文档翻译(三)
- Borrowing treasures from the wealthy: deep transfer learning through selective joint fine-tuning
- 第七周项目2