在MDN文章《面向对象Javascript介绍》中关于继承的部分,我注意到他们设置了prototype.constructor:
// correct the constructor pointer because it points to Person
Student.prototype.constructor = Student;
这有什么重要的目的吗?可以省略吗?
在MDN文章《面向对象Javascript介绍》中关于继承的部分,我注意到他们设置了prototype.constructor:
// correct the constructor pointer because it points to Person
Student.prototype.constructor = Student;
这有什么重要的目的吗?可以省略吗?
当前回答
我不同意。不需要设置原型。取完全相同的代码,但去掉原型。构造函数。有什么变化吗?不。现在,进行以下更改:
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()中设置的任何属性的对象。
这有什么重要的目的吗?
是也不是。
在ES5和更早的版本中,JavaScript本身并不使用构造函数。它定义了函数原型属性的默认对象将拥有它,并且它将引用回函数,就是这样。规范中没有其他内容提到它。
这种情况在ES2015 (ES6)中改变了,它开始在继承层次结构中使用它。例如,Promise#然后在构建要返回的新Promise时使用调用它的Promise的构造函数属性(通过SpeciesConstructor)。它还涉及数组的子类型(通过ArraySpeciesCreate)。
在语言本身之外,有时人们会在试图构建通用的“克隆”函数时使用它,或者只是在他们想要引用他们认为是对象的构造函数时使用它。我的经验是,很少有人使用它,但有时确实有人使用它。
可以省略吗?
它默认存在,你只需要在替换一个函数的prototype属性的对象时把它放回去:
Student.prototype = Object.create(Person.prototype);
如果你不这样做:
Student.prototype.constructor = Student;
...那么Student.prototype.constructor继承自Person。原型(假设)有构造函数= Person。所以这是误导。当然,如果你要子类化一些使用它的东西(比如Promise或Array),而不是使用类¹(它为你处理这个),你会想要确保你正确地设置它。所以基本上,这是个好主意。
如果您的代码(或您使用的库代码)中没有使用它,那也没关系。我一直确保它是正确连接的。
当然,对于ES2015(又名ES6)的class关键字,大多数时候我们会使用它,我们不再需要它了,因为当我们使用它时它已经为我们处理了
class Student extends Person {
}
¹”…如果你正在子类化一些使用它的东西(比如Promise或Array),而不使用class……”-这是可以做到的,但这真的很痛苦(而且有点傻)。你必须使用reflect。construct。
这是不必要的。这只是传统的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。构造函数更正和父引用。
得到了一个很好的代码示例,为什么真的有必要设置原型构造函数..
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 ????
*/
给定简单构造函数:
function Person(){
this.name = 'test';
}
console.log(Person.prototype.constructor) // function Person(){...}
Person.prototype = { //constructor in this case is Object
sayName: function(){
return this.name;
}
}
var person = new Person();
console.log(person instanceof Person); //true
console.log(person.sayName()); //test
console.log(Person.prototype.constructor) // function Object(){...}
默认情况下(来自规范https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/constructor),所有原型都会自动获得一个称为constructor的属性,该属性指向属性所在的函数。 根据构造函数的不同,可能会将其他属性和方法添加到原型中,这不是很常见的做法,但仍然允许进行扩展。
所以简单地回答:我们需要确保原型中的值。构造函数被正确地设置为规范所假定的样子。
我们必须总是正确地设置这个值吗?它有助于调试,并使内部结构与规范保持一致。当我们的API被第三方使用时,我们肯定应该这样做,但当代码最终在运行时执行时,我们不应该这样做。