《JavaScript高级程序设计》第6章补充 继承

基于原型链继承

将父类的实例赋给子类的prototype来实现继承。

原理:父类的实例有父类所有的实例属性和原型方法,将它赋给子类的prototype后,子类的创建的实例就有会__proto__属性指向这个prototype(它拥有父类所有的实例属性和原型方法),实现继承。

function SuperType() {
  this.property = true;
}

SuperType.prototype.getSuperValue = function() {
  return this.property;
}

function SubType() {
  this.subproperty = false;
}

// 关键一步
SubType.prototype = new SuperType();

// 定义自己的方法,注意要放在父类实例赋值之后
SubType.prototype.getSubValue = function () {
  return this.subproperty;
}

原型链继承的问题:本来在父类中的实例属性(如上图property),到了子类中变成了原型属性,这样违反了每个实例有自己独有的实例属性的原则(如果是个数组的话又会一改就全部实例都改了)。

借调用父类的构造函数继承

在子类的构造函数中调用父类的构造函数,同时用call把this绑定在对应的实例上(即目前的this)。

function SuperType() {
  // SubType的实例(instance1、instance2)来到这里之后,color变成了他们的属性(实例属性)
  this.color = ["red", "blue", "green"];
}

// 这里的this是SubType的实例(instance1、instance2),然后借调用父类的构造函数,并把this传进去。
function SubType() {
  SuperType.call(this);
}

var instance1 = new SubType();
instance1.color.push("black");
console.log(instance1.color);

var instance2 = new SubType();
console.log(instance2.color);

借调用构造函数的方式的问题也很明显:所有方法都不能在原型上定义了,本来方法应该要定义在原型中,达到重用的目的。

组合继承

原型链实现对原型属性和方法的继承,借调用构造函数实现对实例属性的继承。

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

SuperType.prototype.sayName = function () {
  console.log(this.name);
}

function SubType(name, age) {
  // 继承父类属性
  SuperType.call(this, name);

  // 添加子类自己的实例属性
  this.age = age;
}

// 继承父类方法(原型方法)
SubType.prototype = new SuperType();   
// 虽然这样color还是变成了SubType的原型属性,但是不要紧,借调用的时候实例会被重新添加一次实例属性color
// 这个实例属性color就会屏蔽掉原型属性color

SubType.prototype.constructor = SubType;

// 添加子类自己的原型方法
SubType.prototype.sayAge = function () {
  console.log(this.age);
}

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

var instance2 = new SuperType("Greg", 27);
console.log(instance2.color);  // ["red", "blue", "green"]

这是最常用的继承模式。

寄生组合式继承

由于子类的prototype并不想要父类的实例属性,我们只想要子类的prototype的__proto__可以指向父类的prototype而已。

所以用 SubType.prototype = new SuperType(); 这种方式实际上不是很完美

// 这个函数的作用简单来说就是输入一个对象,返回一个__proto__指向它的对象
function object(o) {
  function F() {}
  F.prototype = o;
  return new F();
}

// 这个函数的作用就是让子类的prototype的__proto__可以指向父类的prototype
function inheritPrototype(subType, superType) {
  var prototype = object(superType.prototype);
  prototype.constructor = subType;
  subType.prototype = prototype;
}

function SuperType() {
  // 父类的属性
  this.name = name;
  this.color = ["red", "blue", "green"];
}
// 父类的方法
SuperType.prototype.sayName = function () {
  console.log(this.name);
}

function SubType(name, age) {
  // 继承父类属性
  SuperType.call(this, name);
  // 子类自己的属性
  this.age = age;
}
// 继承父类方法(对子类的prototype动手脚),但不是像以前那样简单地 SubType.prototype = new SuperType();
inheritPrototype(SubType, SuperType);
// 子类自己的方法
SubType.prototype.sayAge = function () {
  console.log(this.age);
}

这样SubType.prototype上就不会有不必要的属性了。

posted @ 2016-03-11 20:41  寄生蠕虫  阅读(224)  评论(0编辑  收藏  举报