用户 JonathanLonowski 已经回答了您关于在设置继承时如何避免调用构造的问题。但我也读到你的问题是关于继承如何在 JavaScript 中工作的一般问题。所以这是我试图解释这个话题的尝试:
说到继承,你基本上想做的就是增强原型链。
那么,它的原型链是什么?
当您使用 ie 请求对象的属性时obj.prop
,JavaScript 首先检查该对象obj
是否具有这样的属性。如果没有,它会检查该对象的原型是否具有这样的属性。如果没有,它检查原型的原型是否有这样的属性等等。
当您通过编写使用构造函数创建新对象时,obj = new B()
原型链如下所示:
obj -> B.prototype -> Object -> null
继承如何与原型链一起工作
如果您希望您的B
对象从 type 的对象继承A
,您希望您的原型链看起来像这样:
obj -> B.prototype -> A.prototype -> Object -> null
为了实现这一点,你在之后“打破”原型链B.prototype
并插入完整的原型链A
。或者换句话说,您想设置B.prototype
为指向A.prototype
。
您可以像以前一样执行此操作:
B.prototype = new A();
现在为什么这行得通?所创建的对象new A()
具有以下原型链:
objA -> B.prototype -> Object -> null
如果您B.prototype
使用此对象覆盖,则类型对象的原型链B
如下所示:
objB -> objA -> A.prototype -> Object -> null
如您所见,它有效。通过简单地覆盖B.prototype
,您只会丢失一些属性,例如constructor
属性。因此,如果您尝试获取withconstructor
类型的对象,它首先查找对象本身并没有找到它,然后查找并没有找到它,然后查找并找到它,这是错误的。尽管您并不经常需要该属性,但在覆盖后再次设置它可以被认为是一种好习惯:B
objB.constructor
objA
A.prototype
A
constructor
B.prototype
B.prototype = new A();
B.prototype.constructor = B;
现在,您的方式只是实现原型链链接的一种方式。JonathanLonowski 的解决方案是另一种解决方案,而且确实是更好的解决方案,因为它不调用 function A
。它创建一个空对象,其原型链与 type 对象相同A
:
(empty object) -> A.prototype -> Object -> null
另一种解决方案是不覆盖B.prototype
而是将其修改为简单地指向A.prototype
而不是Object
. 并非每个浏览器都支持这一点,但在某些浏览器中,您可以通过设置__proto__
属性来实现这一点:
B.prototype.__proto__ = A.prototype;
这将产生以下原型链:
obj -> B.prototype -> A.prototype -> Object -> null
请注意,我在这里和那里简化了它,但我认为这应该让您了解它是如何工作的。要理解的最基本的事情是原型设计。现在,从技术上讲,只有一个真正的原型属性,每个对象都有,那就是内部[[prototype]]
属性。您不能直接在 JavaScript 中访问它,但您必须在某些条件下设置.prototype
和.__proto__
操作它。