JavaScript 的原型系统可以解释为对一种面向对象的概念(称为类(class))的某种非正式实现。 类定义了对象的类型的形状 - 它具有什么方法和属性。 这样的对象被称为类的实例(instance)。

原型对于属性来说很实用。一个类的所有实例共享相同的属性值,例如方法。 每个实例上的不同属性,比如我们的兔子的type属性,需要直接存储在对象本身中。

所以为了创建一个给定类的实例,你必须使对象从正确的原型派生,但是你也必须确保,它本身具有这个类的实例应该具有的属性。 这是构造器(constructor)函数的作用。

  1. function makeRabbit(type) {
  2. let rabbit = Object.create(protoRabbit);
  3. rabbit.type = type;
  4. return rabbit;
  5. }

JavaScript 提供了一种方法,来使得更容易定义这种类型的功能。 如果将关键字new放在函数调用之前,则该函数将被视为构造器。 这意味着具有正确原型的对象会自动创建,绑定到函数中的this,并在函数结束时返回。

构造对象时使用的原型对象,可以通过构造器的prototype属性来查找。

  1. function Rabbit(type) {
  2. this.type = type;
  3. }
  4. Rabbit.prototype.speak = function(line) {
  5. console.log(`The ${this.type} rabbit says '${line}'`);
  6. };
  7. let weirdRabbit = new Rabbit("weird");

构造器(实际上是所有函数)都会自动获得一个名为prototype的属性,默认情况下它包含一个普通的,来自Object.prototype的空对象。 如果需要,可以用新对象覆盖它。 或者,你可以将属性添加到现有对象,如示例所示。

按照惯例,构造器的名字是大写的,这样它们可以很容易地与其他函数区分开来。

重要的是,理解原型与构造器关联的方式(通过其prototype属性),与对象拥有原型(可以通过Object.getPrototypeOf查找)的方式之间的区别。 构造器的实际原型是Function.prototype,因为构造器是函数。 它的prototype属性拥有原型,用于通过它创建的实例。

  1. console.log(Object.getPrototypeOf(Rabbit) ==
  2. Function.prototype);
  3. // → true
  4. console.log(Object.getPrototypeOf(weirdRabbit) ==
  5. Rabbit.prototype);
  6. // → true