javascript - 为什么在分配 DerivedClass.prototype 时使用 Object.create 而不是 new Super

标签 javascript inheritance

我一直在阅读有关使用 Javascript 进行面向对象编程的 MDN 指南,其中在展示继承的示例中提到了以下内容:

// Create a Student.prototype object that inherits from Person.prototype.
// Note: A common error here is to use "new Person()" to create the
// Student.prototype. That's incorrect for several reasons, not least 
// that we don't have anything to give Person for the "firstName" 
// argument. The correct place to call Person is above, where we call 
// it from Student.
Student.prototype = Object.create(Person.prototype); // See note below

我也研究了其他答案,但他们没有具体说明使用 Student.prototype = new Person()

会遇到什么问题

上面提到的一个问题与传递 firstName 有关,但这只是一种情况。

在任何人将其标记为重复之前。这里的问题Using "Object.create" instead of "new"处理通常使用 Object.create 而不是构造函数的问题,而不是我要问的问题。

这里的问题What is the reason to use the 'new' keyword at Derived.prototype = new Base处理 foo()new foo()

之间的区别

这个问题的一个答案JavaScript inheritance: Object.create vs new再给一个理由:

When SomeBaseClass has a function body, this would get executed with the new keyword. This usually is not intended - you only want to set up the prototype chain. In some cases it even could cause serious issues because you actually instantiate an object, whose private-scoped variables are shared by all MyClass instances as they inherit the same privileged methods. Other side effects are imaginable.

So, you should generally prefer Object.create. Yet, it is not supported in some legacy browsers; which is the reason you see the new-approach much too frequent as it often does no (obvious) harm. Also have a look at this answer.

阅读以上内容似乎更多地取决于所处理的给定场景。 MDN 是否有严格的理由说使用 new SuperClass() 是不正确的?

最佳答案

TL;DR可以使用 new Person 来构建您的 Student.prototype,但这样做会很复杂您所有的构造函数,限制了它们检测构造错误的能力,并要求所有地方的所有构造函数都处理这种使用形式。由于它更复杂、更容易出错且有局限性,因此大多数人选择了另一条路:Object.create

主要的实用问题是:如果 super 构造函数需要参数怎么办?假设 Person 需要一个名字:

function Person(name) {
    this.name = name;
}

我如何使用 new Person 创建我的原型(prototype)?我没有 name 可以提供。

现在,有两种方法可以解决这个问题:

  1. 要求所有需要参数的构造函数检测到它们在没有参数的情况下被调用,假设它们被调用以构建原型(prototype),并正确处理这种情况。

  2. 改用 Object.create

第一种方式:

// NOT WHAT MOST PEOPLE DO
function Person(name) {
    if (arguments.length === 0) {
        return;
    }
    this.name = name;
}
function Student(name) {
    Person.call(this, name);
}
Student.prototype = new Person;
Student.prototype.constructor = Student;

请注意 Person 必须如何检测到它是在没有参数的情况下被调用的,希望那是因为它被用于创建原型(prototype)而不是出于其他原因,并避免尝试使用缺少的参数.

这很容易出错而且很尴尬,这意味着如果 Person 没有收到最终实例的 name 就不能(例如)引发错误施工电话。它只是不知道为什么要调用它,所以它无法判断没有 name 是否正确。

所以大多数人走另一条路:

// What most people do
function Person(name) {
    this.name = name;
}
function Student(name) {
    Person.call(this, name);
}
Student.prototype = Object.create(Person.prototype);
Student.prototype.constructor = Student;

Person 不必包含任何特殊情况的代码,如果它没有获得 name 并且需要它,可以自由地引发错误。

现在这已经足够根深蒂固了,它被融入到 ES2015(又名 ES6)的 class 关键字中。这个 ES2015 代码:

class Student extends Person {
    constructor(name) {
        super(name);
    }
}

非常接近上面的 Object.create ES5 代码。 (不完全是,但相当接近。)

关于javascript - 为什么在分配 DerivedClass.prototype 时使用 Object.create 而不是 new Super,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33892223/

相关文章:

javascript - JavaScript 中函数内函数 vs 函数返回函数

c++ - 显式切片派生对象

c++ - 抽象类和派生类的输出运算符(<<)

ruby - Ruby Matrix 类的复制/继承(核心/标准库)

qt - 如何重写父类(super class)组件的信号处理程序

javascript - 如何使用 jquery 获取所选引导下拉项的值?

javascript - JavaScript中多向网络的路由或寻路算法

javascript - 使用 Google Analytics 跟踪网站上的社交推文

javascript - 使用 JavaScript 翻转硬币

具有继承性的 Python 循环导入