在ECMAScript中继承主要是依靠原型链来实现的。
利用原型让一个引用类型继承另外一个引用类型的属性和方法
先要了解构造函数、原型、和实例的关系:javascript
<font color="red">每个构造函数都有一个原型对象,原型对象都包含一个指向构造函数的指针,实例都包含一个指向原型对象的内部指针。</font>
实现原型链java
假如原型对象等于另外一个类型的实例,此时该原型对象将包含指向另外一个原型的指针,相应的另外一个原型中也包含着一个指针指向另外一个构造函数的指针。这样层层递进,就构成了实例与原型之间的链条。这就是原型链的基本概念。
判断原型和实例的关系
能够经过两种方式来肯定原型和实例之间关系。数组
alert(instance instanceof Object); //true
alert(Object.prototype.isPrototypeOf(instance)); //true
全部引用类型都默认继承了Object
原型链存在的问题app
在经过原型来实现继承时,原型实际上会变成另外一个类型的实例。原先的实例属性就变成了如今的原型属性了。函数
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属性。 2. 在建立子类型的实例时,不能向超类型的构造函数中传递参数。
解决原型中包含引用类型所带来的问题的过程当中,使用<font color="red">借用构造函数</font>(伪造对象或经典继承)来实现继承。主要是经过使用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构造函数this
相对原型链,借用构造函数能够子类型构造函数中向超类型构造函数传递参数以下:prototype
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. 组合继承
组合继承也叫作<font color="red">伪经典继承</font>将原型链和借用构造函数的技术组合到一块,从而发挥二组之所长的一种继承模式。思路是<font color="red">使用原型链实现对原型属性和方法的继承,而经过借用构造函数来实现对实例属性的继承。</font>设计
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中最经常使用的继承模式。<font color="red">并且instanceOf和isPrototype()也可以识别基于组合继承建立的对象。</font>
### 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高级程序设计》用来作我的笔记的,请大佬们手下留情。