js继承——到继承结束

说到继承,其它语言里可能有两种: 接口继承是继承方法签名,而实现继承则继承实际方法。ES函数没有签名,不能实现接口继承,只支持实现继承,而实现继承主要依靠原型链。(这两句话,说来轻松,理解来不易,且行且珍惜吧~)。函数

因此,理解原型链是掌握继承的必要条件。一个原型对象等与另外一个类型的实例this

function Parent(){
  this.super = "parent";
  this.friends = ["A", "B", "C"];
}
Parent.prototype.getParentValue = function(){
  return this.super;
}
function Child(){
  this.sub = "Child";
}
Child.prototype = new Parent();
Child.prototype.getChildValue = function(){
  return this.sub;
}
var c1= new Child();
c1.getParentValue();  //"parent"
c1.getChildValue();   //"Child"
c1.constructor === Parent;  //true
c1.constructor === Child;   //false

var c2= new Child(); c2.friends.push("D"); c2.friends //["A", "B", "C", "D"] c1.friends //["A", "B", "C", "D"]

 

为何demo.constructor ===Parent;呢? 由于demo.prototype指向Parent实例,而Parent.prototype.constructor指向Parent,所以demo.constructor继承自 Parent.prototype,因此指向Parent;spa

使用原型练实现继承:说明:不能用对象字面量建立原型方法,由于这样会重写原型链。prototype

       缺点:1.引用类型值的原型属性会被全部实例共享,所以在构造函数中定义属性,但经过原型继承时,一个类型的实例会变成另外一个对象的原型。所以实例中的属性就变成了如今的原型的属性了。2.没有办法在不影响全部对象的状况下,向超类型传参。code

为了解决引用类型带来的问题——>借用构造函数(伪造对象、经典继承 ):在子类型构造函数的内部调用超类型构造函数对象

function Parent(){
  this.friends = ["A", "B", "C"];
}
function Child(){
  Parent.call(this);
  this.age = 23;
}
var c1 = new Child();
var c2 = new Child();
c1.friends.push("D");
c1.friends   //["A", "B", "C", "D"]
c2.friends  //["A", "B", "C"]
c2.age   //23

借用构造函数的缺点:没法避免构造函数模式的缺点,方法不能复用,并且超类原型中的方法,对于子类型是不可见的,因此只能统一使用构造函数模式。blog

为了不这些缺点——>组合继承(伪经典继承):使用原型链实现对原型属性和方法的继承,而经过构造函数实现对实例属性的继承继承

function Parent(name){
  this.name = name || "parent";
  this.friends = ["A", "B", "C"];
}
Parent.prototype.sayName = function (){
    return this.name;
}
function Child(name, age){
   Parent.call(this, name);
   this.age = age;
}
Child.prototype = new Parent();
var c1 = new Child("Tom", 34);
var c2 = new Child("Joe", 22);
c1.friends.push("D");
c2.friends   //["A", "B", "C"]
c1.sayName();   //"Tom"

组合继承避免了原型链和借用构造函数的缺陷,融合了它们的优势。成为js中最经常使用的继承模式。
此外还有几种继承模式——>原型式继承:借用原型基于已有的对象建立新的对象,同时还没必要所以建立自定义类型。接口

function object(o){
  function F(){}
  F.prototype = o;
  return new F();
}
var person = {
   name: "Tom",
   friends: ["A", "B", "C"]
};
var p1= object(person);
p1.name = "Marry";
p1.friends.push("D");
var p2 = object(person);
p2.name = "Joe";
p2.friends.push("E");

person.friends           //["A", "B", "C", "D", "E"]

object()函数中建立了一个临时构造函数,并将传入的对象做为该构造函数的原型。至关于进行一次浅复制。和原型模式同样,引用类型始终会被共享。其中ES5定义了Object.create()方法规范了原型继承。原型链

所以,在不必兴师动众的建立构造函数,而只想让一个对象与另外一个对象保持相似的状况下,原型式模式是个不错的选择。

——>寄生式继承:与原型式继承紧密相关的一种思路,与寄生构造函数和工厂模式相似,即建立一个封装继承过程的函数,该函数在内部以某种方式来加强对象。

function createAnother(o){
  var clone = object(o);
  clone.sayHi = function(){
     return "HI";
  };
   return clone;
}
var person = {
   name: "Tom",
   friends: ["A", "B", "C"]
};
var p = createAnother(person);
p.sayHi()   //"HI"

在主要考虑对象而不是自定义类型和构造函数的状况下,寄生式也是一种有用的模式,object()非必须,任何能返回新对象的函数都适用于此模式
组合模式是最经常使用的继承模式,可是组合模式两次调用超类型构造函数,

为了解决这个问题——>寄生组合模式:使用构造函数继承属性,经过原型链的混成形式继承方法;没必要为了指定子类型的原型而调用超类型的构造函数,咱们可使用寄生式继承继承超类型的原型,而后再将结果指定给子类型的原型。

function inheritPrototype(C, P){
 var prototype = object(P.prototype);
 prototype.constructor = C;
 C.prototype = prototype;
}
function Parent(name){
  this.name = name || "parent";
  this.friends = ["A", "B", "C"];
}
Parent.prototype.sayName = function (){
    return this.name;
}
function Child(name, age){
   Parent.call(this, name);
   this.age = age;
}
inheritPrototype(Child, Parent);
Child.prototype.sayAge = function(){
    return this.age;
};

组合继承模式:集寄生模式和组合模式优势于一身,是实现基于类型继承最有效最理想的方式。

相关文章
相关标签/搜索