①原型链式继承
1 function Person(name){ 2 this.name=name; 3 } 4 5 Person.prototype.getName=function(){ 6 return this.name; 7 } 8 9 function Male(age){ 10 this.age=age; 11 } 12 13 Male.prototype=new Person("John"); 14 15 Male.prototype.getAge=function(){ 16 return this.age; 17 } 18 19 var maleA=new Male(12); 20 console.log(maleA.getAge());//12 21 console.log(maleA.getName());//John 22 23 var maleB=new Male(25); 24 console.log(maleB.getAge());//25 25 console.log(maleB.getName());//John
原型链式继承的实质是重写构造函数的原型对象,代之以一个所要继承的类型的实例。该例子中Male类型继承了Person类型。这种继承方式,所有的子类型共享父类型的属性和方法,因为原型指向的是同一个父类型实例。所以,当任一个子类型实例改变了继承来的原型属性的值,那么其他实例的原型属性的值也将被改变。为了解决这个问题,出现了借用构造函数式继承。
②借用构造函数式继承
1 function Person(name){ 2 this.name=name; 3 } 4 5 Person.prototype.getName=function(){ 6 return this.name; 7 } 8 9 function Male(name,age){ 10 Person.call(this,name); 11 this.age=age; 12 } 13 14 Male.prototype.getAge=function(){ 15 return this.age; 16 } 17 18 var maleA=new Male("A",12); 19 console.log(maleA.getAge());//12 20 console.log(maleA.name);//A 21 console.log(typeof maleA.getName);//undefined 22 23 var maleB=new Male("B",25); 24 console.log(maleB.getAge());//25 25 console.log(maleB.name);//B 26 console.log(typeof maleB.getName);//undefined
借用构造函数式继承的实质是在构造函数内调用父类型的构造函数,那么子类型将继承父类型构造函数内所添加的属性和方法。借用构造函数式继承的优点是可以在继承父类型的时候向父类型的构造函数传递参数,缺点是不能继承定义在父类型原型上的方法和属性。为了解决借用构造函数式继承的这个缺点,出现了组合式继承。
③组合式继承
1 function Person(name){ 2 this.name=name; 3 } 4 5 Person.prototype.getName=function(){ 6 return this.name; 7 } 8 9 function Male(name,age){ 10 Person.call(this,name); 11 this.age=age; 12 } 13 14 Male.prototype=new Person(); 15 16 Male.prototype.getAge=function(){ 17 return this.age; 18 } 19 20 var maleA=new Male("A",12); 21 console.log(maleA.getAge());//12 22 console.log(maleA.name);//A 23 console.log(maleA.getName());//A 24 25 var maleB=new Male("B",25); 26 console.log(maleB.getAge());//25 27 console.log(maleB.name);//B 28 console.log(maleB.getName());//B
组合式继承是将原型链式继承和构造函数式继承组合在一起使用,从而发挥两者的长处。其背后的思路是使用原型链来实现对原型属性和方法的继承,而通过借用构造函数实现对实例属性的继承。这样,既通过在原型上定义方法实现了函数复用,又能保证每个实例都有它自己的属性。
④原型式继承
1 function object(o){ 2 function F(){} 3 F.prototype=o; 4 return new F(); 5 } 6 7 var person={}; 8 person.name='John'; 9 person.getName=function(){ 10 return this.name; 11 } 12 13 var male=object(person); 14 male.age=22; 15 male.getAge=function(){ 16 return this.age; 17 } 18 19 console.log(male.name);//John 20 console.log(male.getName())//John 21 console.log(male.age);//22 22 console.log(male.getAge())//22
原型式继承是基于现有对象然后借助原型创建新的对象,新对象拥有现有对象的所有属性和方法,同时还不用创建自定义类型,其实质上是对现有对象的浅复制,新对象与现有对象共享现有对象的属性和方法。ECMASctipt5通过新增Object.create()方法规范了原型式继承。这个方法接受两个参数,一个用作新对象原型的对象和(可选的)一个为新对象定义额外属性的对象。上面的例子可以改写为:
1 var person={}; 2 person.name='John'; 3 person.getName=function(){ 4 return this.name; 5 } 6 7 var male=Object.create(person,{ 8 age:{ 9 value:22 10 } 11 }); 12 13 male.getAge=function(){ 14 return this.age; 15 } 16 console.log(male.name);//John 17 console.log(male.getName())//John 18 console.log(male.age);//22 19 console.log(male.getAge());//22
⑤寄生式继承
1 function Male(original,age){ 2 var clone=Object.create(original); 3 clone.age=age; 4 clone.getAge=function(){ 5 return this.age; 6 } 7 8 return clone; 9 } 10 11 var person={}; 12 person.name="John"; 13 person.getName=function(){ 14 return this.name; 15 } 16 17 var male=Male(person,22); 18 19 console.log(male.name);//John 20 console.log(male.getName())//John 21 console.log(male.age);//22 22 console.log(male.getAge());//22
寄生式继承与寄生构造函数和工厂模式类似,即创建一个仅用于封装继承过程的函数,该函数在内部以某种方式来增强对象,最后再像真是它做了所有工作一样的返回对象。这种继承方式新对象与现有对象共享现有对象的所有属性和方法。改变先有对象的属性的值,新对象对应属性的值也将改变。原型式继承和寄生式继承,都不能实现函数的复用。为了解决这一问题,出现了寄生组合式继承。
⑥寄生组合式继承
1 function inheritPrototype(subType,superType){ 2 var prototype=Object.create(superType.prototype); 3 prototype.constructor=subType; 4 subType.prototype=prototype; 5 } 6 7 function Person(name){ 8 this.name=name; 9 } 10 11 Person.prototype.getName=function(){ 12 return this.name; 13 } 14 15 function Male(name,age){ 16 Person.call(this,name); 17 this.age=age; 18 } 19 20 inheritPrototype(Male,Person); 21 22 Male.prototype.getAge=function(){ 23 return this.age; 24 } 25 26 var maleA=new Male("A",22) 27 28 console.log(maleA.name);//A 29 console.log(maleA.getName())//A 30 console.log(maleA.age);//22 31 console.log(maleA.getAge());//22
寄生组合式继承,即通过借用构造函数来继承属性,通过原型链的混成形式来继承方法,其背后的基本思路是:不必为了指定子类型的原型而调用父类型的构造函数,我们所需要的无非就是父类型的原型的一个副本而已。本质上,就是使用寄生式继承来继承父类型的原型,然后再将结果指定给子类型的原型。