您的位置:首页 > Web前端 > JavaScript

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上面创建不必要的、多余的属性。与此同时,还可以保持原型链,能够正常使用instanceofisPrototypeOf()
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: