继承

原文链接:http://dailyjs.com/post/js101-prototype-chains

继承链和构造函数

如之前所见,JavaScript 对象拥有一个 prototype 属性,它被设计用来实现继承。一个对象的 prototype 属性可以被设置为另一个对象的实例,以此创建一个继承链:

function Shape(name) {
  this.x = 0;
  this.y = 0;
  this.name = name;
  console.log('Shape constructor called');
}

Shape.prototype = {
  move: function(x, y) {
    this.x += x;
    this.y += y;
  },

  toString: function() {
    return 'name: ' + this.name + ', at x: ' + this.x + ', y:' + this.y;
  }
};

// Rectangle
function Rectangle(name) {
  this.name = name;
  console.log('Rectangle constructor called');
}

Rectangle.prototype = new Shape();

var rect = new Rectangle('Player 1');
rect.move(1, 1);
console.log(rect.toString());
console.log(rect instanceof Rectangle);

运行会显示下面的输出:

Shape constructor called
Rectangle constructor called
name: Player 1, at x: 1, y:1
true

注意无论 Shape 还是 Rectangle 构造函数都被调用了。这是因为这一行 Rectangle.prototype = new Shape();

另外需要注意到 rect.moverect.toString 会从 Shape.prototype 中调用方法。当解释器检查一个属性,首先会在当前对象中查找。如果没有找到属性,则会在对象的原型中查找,并以此类推。这就是原型链:

首先在被涉及的对象中直接查找属性,如果对象包含该命名属性,则引用此命名属性;如果对象不包含该命名属性,对象的原型会被检查;以此类推。

-- Annotated ECMAScript 5.1

调用父级方法

如果 Rectangle 想要一个不同的 move 方法,但想重用 Shape 中初始的方法,那么完全可以使用 Function.prototype.apply 来实现:

Rectangle.prototype.move = function(x, y) {
  console.log('Super method called');
  Shape.prototype.move.apply(this, arguments);
};

尽管 Shape.prototype.move.apply 看起来很复杂,但如果我们把它分解,实际上很简单:

  1. 我们想要调用来自 Shapemove 方法
  2. 此方法保存在 Shape.prototype.move
  3. 因为它是一个 Function,所以有一些我们可用的方法(函数是对象!)
  4. apply 特别的允许我们调用函数,而无需创建一个新实例
  5. 它还允许我们提供一个 this 值,以及一个参数数组

当一个函数执行时,参数对象由解释器创建。this 对象是另外一个故事了 -- 到目前为止我假设你已经直观的理解它是什么了,但我们会在接下来的部分更详细的看看它。

引用

Fork me on GitHub