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

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

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


当前回答

它并不总是必要的,但它确实有它的用途。假设我们想在基类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

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

// 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

其他回答

它并不总是必要的,但它确实有它的用途。假设我们想在基类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

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

// 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

编辑,其实我错了。注释掉一行并不会改变它的行为。(我测试过)


是的,这是必要的。当你这样做时

Student.prototype = new Person();  

student。prototype。constructor变成Person。因此,调用Student()将返回Person创建的对象。如果你这样做了

Student.prototype.constructor = Student; 

Student.prototype.constructor被重置回Student。现在,当您调用Student()时,它执行Student,它调用父构造函数parent(),它返回正确继承的对象。如果你在调用Student.prototype.constructor之前没有重置它,你将得到一个没有在Student()中设置的任何属性的对象。

现在不需要加糖的函数'类'或使用'New'。使用对象字面量。

Object原型已经是一个“类”。当你定义一个对象文字时,它已经是原型对象的一个实例。这些也可以作为另一个对象的原型,等等。

const Person = {
  name: '[Person.name]',
  greeting: function() {
    console.log( `My name is ${ this.name || '[Name not assigned]' }` );
  }
};
// Person.greeting = function() {...} // or define outside the obj if you must

// Object.create version
const john = Object.create( Person );
john.name = 'John';
console.log( john.name ); // John
john.greeting(); // My name is John 
// Define new greeting method
john.greeting = function() {
    console.log( `Hi, my name is ${ this.name }` )
};
john.greeting(); // Hi, my name is John

// Object.assign version
const jane = Object.assign( Person, { name: 'Jane' } );
console.log( jane.name ); // Jane
// Original greeting
jane.greeting(); // My name is Jane 

// Original Person obj is unaffected
console.log( Person.name ); // [Person.name]
console.log( Person.greeting() ); // My name is [Person.name]

这里值得一读:

Class-based object-oriented languages, such as Java and C++, are founded on the concept of two distinct entities: classes and instances. ... A prototype-based language, such as JavaScript, does not make this distinction: it simply has objects. A prototype-based language has the notion of a prototypical object, an object used as a template from which to get the initial properties for a new object. Any object can specify its own properties, either when you create it or at run time. In addition, any object can be associated as the prototype for another object, allowing the second object to share the first object's properties

到目前为止,困惑仍然存在。

按照原来的例子,你有一个现有的对象student1 as:

var student1 = new Student("Janet", "Applied Physics");

假设你不想知道student1是如何创建的,你只是想要另一个类似的对象,你可以使用student1的构造函数属性:

var student2 = new student1.constructor("Mark", "Object-Oriented JavaScript");

在这里,如果没有设置构造函数属性,它将无法从Student获取属性。相反,它将创建一个Person对象。

这是不必要的。这只是传统的OOP拥护者所做的许多事情之一,他们试图将JavaScript的原型继承转变为经典继承。唯一的事情是,下面

Student.prototype.constructor = Student; 

你现在有了当前“构造函数”的引用。

在Wayne的答案中,它被标记为正确,你可以做与下面代码完全相同的事情

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

使用下面的代码(只需替换此代码。构造师与Person)

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

感谢上帝,在ES6中,经典继承主义者可以使用语言的原生操作符,如class、extends和super,我们不必看到prototype。构造函数更正和父引用。