JavaScript继承实现方式
2018-03-19 11:39
295 查看
前言
ECMAScript只支持实现继承,主要依赖原型链实现。原型链实现继承
基本思想:使原型对象等于另一个类型的实例。示例:
function SuperType(){ this.property = true; } SuperType.prototype.getSuperValue = function(){ return this.property; } function SubType(){ this.subProperty = false; } //继承SuperType SubType.prototype = new SuperType(); SubType.prototype.getSubValue = function(){ return this.subProperty; } var instance = new SubType(); console.log(instance.getSuperValue());//true
原型链存在的问题:
1:当超类型中存在引用类型属性时,如果子类型的一个实例去修改此属性,能够通过其他子类型的实例反映出来。
2:无法在不影响所有对象实例的情况下,给超类型的构造函数传递参数。
借用构造函数(经典继承)
基本思想:在子类型的构造函数内部调用超类型构造函数。示例:
function SuperType(){ this.colors = ["red","yellow","blue"]; } function SubType(){ //继承了SuperType SuperType.call(this); } var instance1 = new SubType(); instance1.colors.push("green"); console.log(instance1.colors)//["red","yellow","blue","green"] var instance2 = new SubType() 4000 ; console.log(instance2.colors);//["red","yellow","blue"]
可以在子类型构造函数中向超类型构造函数传递参数。
function SuperType(name){ this.name = name; } function SubType(){ //继承了SuperType SuperType.call(this,"James"); }
借用构造函数的问题
1:方法都在构造函数中定义,函数无法复用;
2:在超类型的原型中定义的方法,对于子类型而言是不可见的,也 就是说,超类型无法使用原型模式等其他模式,只能使用构造函数模式。
组合继承(伪经典继承)
基本思想:将原型链和借用构造函数的技术组合到一起,使用原型链实现对原型属性和方法的继承,通过借用构造函数实现对实例属性的继承。这样既可以通过在原型上定义定义方法实现函数的复用,又能保证每个实例都有自己的属性。
示例:
function SuperType(name){ this.name = name; this.colors = ["red","yellow"]; } SuperType.prototype.sayName = function(){ console.log(this.name); } function SubType(name,age){ //继承属性 SuperType.call(this,name); this.age = age; } //继承方法 SubType.prototype = new SuperType(); SubType.prototype.sayAge = function(){ console.log(this.age); } var instance1 = new SubType("James",28); instance1.colors.push("blue"); var instance2 = new SubType("Harden","26"); console.log(instance1.colors);//["red", "yellow", "blue"] console.log(instance2.colors);//["red", "yellow"] console.log(instance1.sayAge());//28 console.log(instance2.sayAge());//26 console.log(instance1.sayName());//"James" console.log(instance2.sayName());//"Harden"
组合继承实JavaScript中最常用的继承模式。而且,instanceof和isPrototypeof() 也能够识别基于组合继承创建的对象。
问题:
无论在什么情况下,都会调用两次超类型构造函数,一次是在创建子类型原型的时候,一次是在子构造函数内部。也就是说,子类型会包含超类型对象的所有实例属性,但是在调用子类型构造函数的时候,会再次重写这些属性。
原型式继承
思路:借助原型可以基于已有的对象创建新对象,同时还不必因此创建自定义类型。示例:
function object(o){ function F(){} F.prototype = o; return new F(); }
从本质上讲,上述object()对传入的对象o执行了一次浅复制,也就是说,o中若有属性存的是引用类型值,那么一个实例去操作这个属性,会在其他实例上反映出来。
举例:
var person = { name:"James", colors:["red","yellow"] } var person1 = object(person); person1.name = "Harden"; person1.colors.push("blue"); var person2 = object(person); person2.name = "Cp3"; console.log(person1.name);//"Harden" console.log(person1.colors);//["red", "yellow", "blue"] console.log(person2.name);//"Cp3" console.log(person2.colors);//["red", "yellow", "blue"]
原型式继承要求必须有一个对象作为另一个对象的基础。
ECMAScript5通过新增Object.create()规范化了原型式继承。该方法接收两个参数:一个作为新对象原型的对象和一个为新对象定义额外属性的对象,第二个参数可选。
示例:
var person ={ name:"James", color:["red","yellow"] } var newPerson = Object.create(person,{ name:{ value:"Harden" } }); console.log(newPerson.name)//"Harden"
Object.create()第二个参数的格式与Object.defineProperties()方法的第二个参数的格式相同。
寄生式继承模式
思路:和寄生构造函数和工厂模式类似,即创建一个用于封装继承过程的函数,该函数在内部以某种形式加强对象,最后返回对象。function createPerson(original){ //创建一个新对象 var clone = Object.create(original); //以某种方式增强对象 clone.sayHi = function(){ console.log("Hi"); } //返回对象 return clone; } var person = { name:"James", colors:["red","yellow"] } var anotherPerson = createPerson(person); anotherPerson.sayHi();//"Hi" anotherPerson.colors.push("blue"); console.log(anotherPerson.colors);//["red","yellow","blue"]
上述代码生成新对象使用的Object.create()方法,不是必需的,任何返回新对象的函数都适用于此模式。
在主要考虑从对象出发,而不是自定义类型和构造函数的情况下,寄生式继承也是一种有用的模式。
问题:
使用寄生式继承为对象添加函数,同样做不到函数复用而降低效率。
寄生组合式继承
前面说过,组合继承也是存在两次调用超类型构造函数的问题的。基本思路:不必为了创建子类型的原型而去调用超类型的构造函数,我们需要的无非就是超类型原型的一个副本。
寄生组合式继承模式:
function inheritPrototype(superType,subType){ //创建对象 var prototype = Object.create(superType.prototype); //增强对象 prototype.constructor = subType; //指定原型对象 subType.prototype = prototype; }
示例:
function SuperType(name){ this.name = name; this.colors = ["red","yellow"]; } SuperType.prototype.sayName = function(){ console.log(this.name); } function SubType(name,age){ SuperType.call(this,name); this.age = age; } inheritPrototype(SuperType,SubType); SubType.prototype.sayAge = function(){ console.log(this.age); } var person1 = new SubType("James",28); person1.sayName();//"James" person1.sayAge();//28 console.log(person1.colors);//["red","yellow"]
上述例子的高效体现在它只调用了一次SuperType构造函数,并且因此避免了在SubType.prototype上面创建不必要的、多余的属性。与此同时,还可以保持原型链,能够正常使用instanceof和isPrototypeOf()。
相关文章推荐
- 基于JavaScript实现继承机制之构造函数+原型链混合方式的使用详解
- javascript实现继承的几种方式
- 讲述Javascript 实现继承的方式(基础知识)
- 详述JavaScript实现继承的几种方式
- JavaScript继承实现方式一览
- 推荐JavaScript实现继承的最佳方式
- (转)js(javascript) 继承的5种实现方式
- javaScript实现继承的5种方式
- 推荐JavaScript实现继承的最佳方式
- javascript——实现继承的6种方式
- javascript实现继承的方式
- javascript实现继承的几种方式
- Javascript继承实现方式
- JavaScript实现继承(六种方式)
- javascript实现继承的几种方式
- JavaScript 中实现继承的方式(列举3种在前一章,我们曾经讲解过创建类的最好方式是用构造函数定义属性,用原型定义方法。)
- 秒懂JavaScript继承和实现方式
- javascript中实现继承的最佳方式
- 从继承方式的实现看javascript语言的设计初衷
- JavaScript实现继承的方式优化