js实现继承的几种方法

367 阅读4分钟

继承

在ECMAScript中继承主要是依靠原型链来实现的。

  • 实现继承的方法

利用原型让一个引用类型继承另一个引用类型的属性和方法

什么是原型链

  • 先要了解构造函数、原型、和实例的关系: 每一个构造函数都有一个原型对象,原型对象都包含一个指向构造函数的指针,实例都包含一个指向原型对象的内部指针。

  • 实现原型链 假如原型对象等于另一个类型的实例,此时该原型对象将包含指向另一个原型的指针,相应的另一个原型中也包含着一个指针指向另一个构造函数的指针。这样层层递进,就构成了实例与原型之间的链条。这就是原型链的基本概念。

  • 判断原型和实例的关系 可以通过两种方式来确定原型和实例之间关系。

    1. 使用instanceof操作符,只要用这个操作符来测试实例和原型链中出现的构造函数,结果就一定返回true。
    alert(instance instanceof Object); //true  
    
    1. 使用isprototypeOf()方法,同样只要是原型链中出现过得原型,都可以说是原型链所派生的实例的原型。isportotypeOf()也会返回true
alert(Object.prototype.isPrototypeOf(instance)); //true

所有引用类型都默认继承了Object

  1. 原型链存在的问题

    1. 在通过原型来实现继承时,原型实际上会变成另一个类型的实例。原先的实例属性就变成了现在的原型属性了。
    function SuperType(){
    	this.color=["red","blue","green"]
    }
    
    function SubType(){
    }
    SubType.prototype = new SuperType();//继承了SuperType();
    
    var instance1 = new SubType();
    instance1.color.push("black");
    console.log(instance1.color); //"red,blue,green,black"
    
    var instance2 = new SubType();
    console.log(instance2.color); //"red,blue,green,black"
    

    SuperType构造函数定义了一个colors属性,SuperType的每个实例都会有各自包含自己数组的color属性。当SubType通过原型链继承了SuperType之后,subType.prototype就变成了SuperType的一个实例,因此它也就拥有了自己的color属性。那SubType的所有实例都会共享这个color属性。

    1. 在创建子类型的实例时,不能向超类型的构造函数中传递参数。

实现继承的方法

1. 借用构造函数

解决原型中包含引用类型所带来的问题的过程中,使用借用构造函数(伪造对象或经典继承)来实现继承。主要是通过使用apply()和call()方法在新创建的对象上执行构造函数如下:

function SuperType(){
	this.color=["red","blue","green"]
}

function SubType(){
	//继承了SuperType
	SuperType.call(this);
}

var instance1 = new SubType();
instance1.color.push("black");
console.log(instance1.color) //"red, blue,green,black"

var instance2 = new SubType();
console.log(instance2.color) //"red,blue,green"

通过call()或apply()方法在新创建的SubType实例的环境下调用了SuperType构造函数

相对原型链,借用构造函数可以子类型构造函数中向超类型构造函数传递参数如下:

function SuperType(name){
	this.name=name;
}
function SubType(){
	//继承了SuperType 同时还传递了参数
	SuperType.call(this,"aa");
	//实例属性
	this.age=29;
}

var instance = new SubType();
alert(instance.name) // aa
alert(instance.age) //29

2. 组合继承

组合继承也叫做伪经典继承将原型链和借用构造函数的技术组合到一块,从而发挥二组之所长的一种继承模式。思路是使用原型链实现对原型属性和方法的继承,而通过借用构造函数来实现对实例属性的继承。

function SuperType(name){
	this.name=name;
   this.color = ["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("aaa",29);
instance1.color.push("black");
alert(instance1.color); //"red,blue,green,black"
instance1.sayName(); //"aaa"
instance1.sayAge(); // 29

 var instance2 = new SubType("ccc",30);
alert(instance2.color); //"red,blue,green"
instance2.sayName(); //"ccc"
instance2.sayAge(); // 30

组合继承避免了原型链和借用构造函数的缺陷,融合了他们的优点,成为JavaScript中最常用的继承模式。而且instanceOf和isPrototype()也能够识别基于组合继承创建的对象。

3. 原型式继承

借用原型可以基于已有的对象创建新对象,同时还不必因此创建自定义类型。

var person = {
	name:"Nicholas",
	friends:["Shelby","court","Van"]
};

var anotherPerson = Object.create(person);
anotherPerson.name = "Greg";
anotherPerson.friends.push("Rob");

var yetAnotherPerson = Object.create(person);
yetAnotherPerson.name = "Linda";
yetAnotherPerson.friends.push("Barbie");

alert(person.friends) //"Shelby,Count,Van,Rob,Barbie"

Object.create()传递第二个参数

var person = {
	name: "Nicholas",
	friends: ["Shelby","Court","Van"]
}

var anotherPerson = Object.create(person,{
	name: {
		value: "Greg"
	}
});

var anotherPerson2 = Object.create(person,{
	name: {
		value: "blue"
	}
});
alert(anotherPerson.name) //"Greg"
alert(anotherPerson2.name) //"blue"

Obeject.create()方法IE9开始兼容

4. 寄生式继承

寄生式继承的思路与寄生构造函数和工厂模式类似,即创建一个仅用于封装继承过程的函数,该函数在内部以某种方式来增强对象,最后再像·真地是它做了所有工作一样返回对象。

function createAnother(original) {
	var clone = object(original);
	clone.sayHi = function(){
		alert("hi");
	};
	return clone;
}

var person = {
	name: "Nicholas",
	friends: ["Shelby","Court","Van"]
};

var anotherPerson = createAnother(person);
anotherPerson.sayHi(); //"hi"

本文主要是个人摘自《javascript高级程序设计》用来做个人笔记的,请大佬们手下留情。