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

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

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


当前回答

得到了一个很好的代码示例,为什么真的有必要设置原型构造函数..

function CarFactory(name){ 
   this.name=name;  
} 
CarFactory.prototype.CreateNewCar = function(){ 
    return new this.constructor("New Car "+ this.name); 
} 
CarFactory.prototype.toString=function(){ 
    return 'Car Factory ' + this.name;
} 

AudiFactory.prototype = new CarFactory();      // Here's where the inheritance occurs 
AudiFactory.prototype.constructor=AudiFactory;       // Otherwise instances of Audi would have a constructor of Car 

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

AudiFactory.prototype.toString=function(){ 
    return 'Audi Factory ' + this.name;
} 

var myAudiFactory = new AudiFactory('');
  alert('Hay your new ' + myAudiFactory + ' is ready.. Start Producing new audi cars !!! ');            

var newCar =  myAudiFactory.CreateNewCar(); // calls a method inherited from CarFactory 
alert(newCar); 

/*
Without resetting prototype constructor back to instance, new cars will not come from New Audi factory, Instead it will come from car factory ( base class )..   Dont we want our new car from Audi factory ???? 
*/

其他回答

我不同意。不需要设置原型。取完全相同的代码,但去掉原型。构造函数。有什么变化吗?不。现在,进行以下更改:

Person = function () {
    this.favoriteColor = 'black';
}

Student = function () {
    Person.call(this);
    this.favoriteColor = 'blue';
}

在测试代码的末尾……

alert(student1.favoriteColor);

颜色是蓝色的。

对原型的更改。构造函数,根据我的经验,没有做太多,除非你做非常具体,非常复杂的事情,这可能不是一个好的实践:)

Edit: After poking around the web for a bit and doing some experimentation, it looks like people set the constructor so that it 'looks' like the thing that is being constructed with 'new'. I guess I would argue that the problem with this is that javascript is a prototype language - there is no such thing as inheritence. But most programmers come from a background of programming that pushes inheritence as 'the way'. So we come up with all sorts of things to try and make this prototypical language a 'classic' language.. such as extending 'classes'. Really, in the example they gave, a new student is a person - it isn't 'extending' from another student.. the student is all about the person, and whatever the person is the student is as well. Extend the student, and whatever you've extended is a student at heart, but is customized to fit your needs.

克罗克福德有点疯狂和过分热心,但认真阅读他写的一些东西。它会让你从不同的角度看待这个问题。

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


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

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()中设置的任何属性的对象。

当你需要toString的替代而不需要monkeypatching时,它是必要的:

//Local foo = []; foo.toUpperCase = String(foo).toUpperCase; foo.push("a"); foo.toUpperCase(); //Global foo = []; window.toUpperCase = function (obj) {return String(obj).toUpperCase();} foo.push("a"); toUpperCase(foo); //Prototype foo = []; Array.prototype.toUpperCase = String.prototype.toUpperCase; foo.push("a"); foo.toUpperCase(); //toString alternative via Prototype constructor foo = []; Array.prototype.constructor = String.prototype.toUpperCase; foo.push("a,b"); foo.constructor(); //toString override var foo = []; foo.push("a"); var bar = String(foo); foo.toString = function() { return bar.toUpperCase(); } foo.toString(); //Object prototype as a function Math.prototype = function(char){return Math.prototype[char]}; Math.prototype.constructor = function() { var i = 0, unicode = {}, zero_padding = "0000", max = 9999; while (i < max) { Math.prototype[String.fromCharCode(parseInt(i, 16))] = ("u" + zero_padding + i).substr(-4); i = i + 1; } } Math.prototype.constructor(); console.log(Math.prototype("a") ); console.log(Math.prototype["a"] ); console.log(Math.prototype("a") === Math.prototype["a"]);

得到了一个很好的代码示例,为什么真的有必要设置原型构造函数..

function CarFactory(name){ 
   this.name=name;  
} 
CarFactory.prototype.CreateNewCar = function(){ 
    return new this.constructor("New Car "+ this.name); 
} 
CarFactory.prototype.toString=function(){ 
    return 'Car Factory ' + this.name;
} 

AudiFactory.prototype = new CarFactory();      // Here's where the inheritance occurs 
AudiFactory.prototype.constructor=AudiFactory;       // Otherwise instances of Audi would have a constructor of Car 

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

AudiFactory.prototype.toString=function(){ 
    return 'Audi Factory ' + this.name;
} 

var myAudiFactory = new AudiFactory('');
  alert('Hay your new ' + myAudiFactory + ' is ready.. Start Producing new audi cars !!! ');            

var newCar =  myAudiFactory.CreateNewCar(); // calls a method inherited from CarFactory 
alert(newCar); 

/*
Without resetting prototype constructor back to instance, new cars will not come from New Audi factory, Instead it will come from car factory ( base class )..   Dont we want our new car from Audi factory ???? 
*/

这有一个巨大的陷阱,如果你写

Student.prototype.constructor = Student;

但如果有一个老师,他的原型也是人,你写

Teacher.prototype.constructor = Teacher;

那么学生构造函数现在是老师!

编辑: 您可以通过确保您已经使用使用Object创建的Person类的新实例设置了Student和Teacher原型来避免这种情况。创建,如Mozilla示例中所示。

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