回到课程
本资料仅提供以下语言版本:English。请 帮助我们 将其翻译为 简体中文 版本。

类继承自对象?

重要程度: 5

正如我们所知道的那样,所有的对象通常都继承自 Object.prototype,并且可以访问像 hasOwnProperty 那样的通用方法。

举个例子:

class Rabbit {
  constructor(name) {
    this.name = name;
  }
}

let rabbit = new Rabbit("Rab");

// hasOwnProperty 方法来自 Object.prototype
// rabbit.__proto__ === Object.prototype
alert( rabbit.hasOwnProperty('name') ); // true

但是如果我们明确的拼出 "class Rabbit extends Object",那么结果会和简单的 "class Rabbit" 有所不同么?

如果有的话,不同之处又在哪?

这里是示例代码(它确实无法运行了,原因是什么?请解决它):

class Rabbit extends Object {
  constructor(name) {
    this.name = name;
  }
}

let rabbit = new Rabbit("Rab");

alert( rabbit.hasOwnProperty('name') ); // true

首先,让我们看看为什么之前的代码无法运行。

如果我们尝试运行它,就会发现明显的原因。派生类的构造函数必须调用 super()。否则不会定义 "this"

这里就是解决问题的代码:

class Rabbit extends Object {
  constructor(name) {
    super(); // 需要在继承时调用父类的构造函数
    this.name = name;
  }
}

let rabbit = new Rabbit("Rab");

alert( rabbit.hasOwnProperty('name') ); // true

但这还不是全部原因。

即便是修复了问题,"class Rabbit extends Object"class Rabbit 仍然存在着重要差异。

我们知道,“extends” 语法会设置两个原型:

  1. 在构造函数的 "prototype" 之间设置原型(为了获取实例方法)
  2. 在构造函数之间会设置原型(为了获取静态方法)

在我们的例子里,对于 class Rabbit extends Object,它意味着:

class Rabbit extends Object {}

alert( Rabbit.prototype.__proto__ === Object.prototype ); // (1) true
alert( Rabbit.__proto__ === Object ); // (2) true

所以现在 Rabbit 对象可以通过 Rabbit 访问 Object 的静态方法,如下所示:

class Rabbit extends Object {}

// 通常我们调用 Object.getOwnPropertyNames
alert ( Rabbit.getOwnPropertyNames({a: 1, b: 2})); // a,b

但是如果我们没有声明 extends Object,那么 Rabbit.__proto__ 将不会被设置为 Object

这里有个示例:

class Rabbit {}

alert( Rabbit.prototype.__proto__ === Object.prototype ); // (1) true
alert( Rabbit.__proto__ === Object ); // (2) false (!)
alert( Rabbit.__proto__ === Function.prototype ); // 所有函数都是默认如此

// 报错,Rabbit 上没有对应的函数
alert ( Rabbit.getOwnPropertyNames({a: 1, b: 2})); // Error

所以在这种情况下,Rabbit 无法访问 Object 的静态方法。

顺便说一下,Function.prototype 也有一些函数的通用方法,比如 callbind 等等。在上述的两种情况下他们都是可用的,因为对于内置的 Object 构造函数来说,Object.__proto__ === Function.prototype

这里有一张图来解释:

所以,简而言之,这里有两点区别:

class Rabbit class Rabbit extends Object
needs to call super() in constructor
Rabbit.__proto__ === Function.prototype Rabbit.__proto__ === Object