我尝试在JavaScript中理解基于原型的继承。要使用构造函数建立原型链,通常可以这样做:
function Person( name, gender ){
this.name = name;
this.gender = gender;
}
function Male( name ){
Person.call(this, name, "male");
}
Male.prototype = Object.create( Person.prototype );
Object.defineProperty( Male.prototype, "constructor", {
enumerable: false, value: Male, writeable: true
});
var person1 = new Male( "Chris" );
因此,对于Male.prototype
,您创建了一个全新的对象,其内部[[prototype]]属性设置为父对象。因为它是一个新对象,所以仍然需要添加一个不可枚举的constructor
属性。
由于有办法直接设置[[prototype]]
属性,我想知道为什么你不能这样做:
function Person( name, gender ){
this.name = name;
this.gender = gender;
}
function Male( name ){
Person.call(this, name, "male");
}
Object.setPrototypeOf( Male.prototype, Person.prototype );
var person1 = new Male( "Chris" );
使用此解决方案,您只需将[[prototype]]
Male.prototype
属性设置为父对象即可。 (在ES6之前,您可以使用__proto__
属性来设置原型。)您不需要创建新对象(因为据我所知,js运行时自动为每个函数附加一个新的prototype
对象,并且您不需要显式创建正确的constructor
属性,因为它已经存在。
我的问题是:为什么没有人使用这种方法来设置原型链?问题在哪里?
答案 0 :(得分:0)
这是一个有趣的问题。我不知道setPrototypeOf方法的存在。显然,性能比使用Object.create
更差的链接中查看更多内容如果您关心性能,则应避免设置对象的[[Prototype]]。而是使用Object.create()创建一个具有所需[[Prototype]]的新对象。
答案 1 :(得分:0)
前几天我有同样的疑问,我在这里问了一下:https://softwareengineering.stackexchange.com/questions/343778/when-doing-inheritance-why-not-simply-modify-the-prototype-property-of-the
显然,我们不应该做Object.setPrototypeOf( Child.prototype, Parent.prototype )
为什么没有真正的共识,但是Mozilla(MDN)会向我们发出一般警告。
警告:根据现代JavaScript引擎如何在每个浏览器和JavaScript引擎中优化属性访问,非常慢的操作,改变对象的[[Prototype]]。改变继承对性能的影响是微妙和遥远的,并不仅仅局限于在obj .__ proto__ = ...语句中花费的时间,而是可以扩展到任何可以访问任何[[Prototype]的对象的代码。 ]已被改变。如果您关心性能,则应避免设置对象的[[Prototype]]。而是使用Object.create()创建一个具有所需[[Prototype]]的新对象。
底线是:不要这样做!
它滋生了代码中的不确定性。
答案 2 :(得分:-1)
这是一个微妙但非常重要的观点。如果您将Male
原型设置为Person
原型,他们将共享 ONE 对象实例。对Person
原型的任何更改都会影响Person
和Male
对象 的所有实例,反之亦然 。现在,最初,这似乎是期望的行为,但你必须在这里将“类型”的概念与“实例”分开。
通过Male
新的 Person
实例作为其原型,您将获得继承的好处, 但是您从所有Person
个实例将使用的实例中解析所有Person
个实例正在使用的Male
的实际实例 。
这使您可以对Male.prototype
进行更改,而不会影响任何Person
实例。