为什么需要设置原型构造函数?

2022-08-29 23:56:48

MDN文章面向对象Javascript简介中关于继承的部分,我注意到他们设置了protype.constructor:

// correct the constructor pointer because it points to Person
Student.prototype.constructor = Student;  

这有什么重要目的吗?可以省略它吗?


答案 1

它并不总是必要的,但它确实有其用途。假设我们要在基类上创建一个复制方法。喜欢这个:Person

// define the Person Class  
function Person(name) {
    this.name = name;
}  

Person.prototype.copy = function() {  
    // return new Person(this.name); // just as bad
    return new this.constructor(this.name);
};  

// define the Student class  
function Student(name) {  
    Person.call(this, name);
}  

// inherit Person  
Student.prototype = Object.create(Person.prototype);

现在,当我们创建一个新的并复制它时会发生什么?Student

var student1 = new Student("trinth");  
console.log(student1.copy() instanceof Student); // => false

副本不是 的实例。这是因为(如果没有显式检查),我们将无法从“基”类返回副本。我们只能返回 .但是,如果我们重置了构造函数:StudentStudentPerson

// correct the constructor pointer because it points to Person  
Student.prototype.constructor = Student;

...然后一切按预期工作:

var student1 = new Student("trinth");  
console.log(student1.copy() instanceof Student); // => true

答案 2

这有什么重要目的吗?

是和否。

在ES5及更早版本中,JavaScript本身并没有用于任何事情。它定义了函数属性上的默认对象将具有它,并且它将引用回函数,仅此而已。规范中根本没有其他任何内容提及它。constructorprototype

这在ES2015(ES6)中发生了变化,它开始在继承层次结构中使用它。例如,Promise#然后在构建返回的新 promise 时使用您调用它(通过 SpeciesConstructor)的承诺的属性。它还参与子类型化数组(通过ArraySpeciesCreate)。constructor

在语言本身之外,有时人们在尝试构建通用的“克隆”函数时会使用它,或者只是在他们想要引用他们认为是对象的构造函数时使用它。我的经验是,使用它很少见,但有时人们确实使用它。

可以省略它吗?

默认情况下,它在那里,只需在替换函数属性上的对象时将其放回原处:prototype

Student.prototype = Object.create(Person.prototype);

如果不这样做:

Student.prototype.constructor = Student;

...然后继承(大概)具有 .所以这是误导性的。当然,如果你正在子类化使用它的东西(如或),而不是使用¹(它为你处理这个问题),你需要确保你设置正确。所以基本上:这是一个好主意。Student.prototype.constructorPerson.prototypeconstructor = PersonPromiseArrayclass

如果您的代码(或您使用的库代码)中没有任何内容使用它,则没关系。我一直确保它已正确连接。

当然,对于ES2015(又名ES6)的关键字,大多数时候我们会使用它,我们不必再使用它了,因为当我们这样做时,它会为我们处理。class

class Student extends Person {
}

¹ “...如果你正在子类化使用它的东西(如PromiseArray)而不是使用class......“——这是可能的,但这是一个真正的痛苦(而且有点傻)。你必须使用Refle.construct