考虑以下代码。
function a() {}
function b() {}
function c() {}
b.prototype = new a();
c.prototype = new b();
console.log((new a()).constructor); //a()
console.log((new b()).constructor); //a()
console.log((new c()).constructor); //a()
此外,请考虑以下事项。
console.log(new a() instanceof a); //true
console.log(new b() instanceof b); //true
console.log(new c() instanceof c); //true
(new c()).constructor
等于 a()
和 Object.getPrototypeOf(new c())
是 a{ }
, instanceof
怎么可能要知道new c()
是 c
的一个实例? 最佳答案
好吧,让我们来玩一个小游戏:
从上图我们可以看出:
function Foo() {}
这样的函数时, JavaScript 创建一个 Function
实例。 Function
实例(构造函数)有一个属性 prototype
这是一个指针。 prototype
构造函数的属性指向它的原型(prototype)对象。 constructor
这也是一个指针。 constructor
原型(prototype)对象的属性指向其构造函数。 Foo
的新实例时喜欢 new Foo()
, JavaScript 创建一个新对象。 [[proto]]
实例的属性指向构造函数的原型(prototype)。 现在,问题出现了,为什么 JavaScript 不附加
constructor
属性到实例对象而不是原型(prototype)。考虑:function defclass(prototype) {
var constructor = prototype.constructor;
constructor.prototype = prototype;
return constructor;
}
var Square = defclass({
constructor: function (side) {
this.side = side;
},
area: function () {
return this.side * this.side;
}
});
var square = new Square(10);
alert(square.area()); // 100
如您所见
constructor
property 只是原型(prototype)的另一种方法,如 area
在上面的例子中。是什么让 constructor
属性的特殊之处在于它用于初始化原型(prototype)的一个实例。否则它与原型(prototype)的任何其他方法完全相同。定义
constructor
由于以下原因,原型(prototype)上的属性是有利的:Object.prototype
. constructor
Object.prototype
的属性(property)指向 Object
.如果 constructor
属性是在实例上定义的,然后 Object.prototype.constructor
将是 undefined
因为Object.prototype
是 null
的一个实例. new
的工作更容易,因为它不需要定义 constructor
每个实例的属性。 constructor
属性(property)。因此它是有效的。 现在当我们谈论继承时,我们有以下场景:
从上图我们可以看出:
prototype
属性设置为基本构造函数的实例。 [[proto]]
派生构造函数实例的属性也指向它。 constructor
派生构造函数实例的属性现在指向基构造函数。 至于
instanceof
运算符,与流行的看法相反,它不依赖于 constructor
实例的属性。从上面我们可以看到,这会导致错误的结果。instanceof
运算符是二元运算符(它有两个操作数)。它对实例对象和构造函数进行操作。正如 Mozilla Developer Network 上的解释,它只是执行以下操作:function instanceOf(object, constructor) {
while (object != null) {
if (object == constructor.prototype) { //object is instanceof constructor
return true;
} else if (typeof object == 'xml') { //workaround for XML objects
return constructor.prototype == XML.prototype;
}
object = object.__proto__; //traverse the prototype chain
}
return false; //object is not instanceof constructor
}
简单地说,如果
Foo
继承自 Bar
,然后是 Foo
实例的原型(prototype)链将会:foo.__proto__ === Foo.prototype
foo.__proto__.__proto__ === Bar.prototype
foo.__proto__.__proto__.__proto__ === Object.prototype
foo.__proto__.__proto__.__proto__.__proto__ === null
如您所见,每个对象都继承自
Object
构造函数。原型(prototype)链在内部 [[proto]]
结束时结束。属性指向 null
.instanceof
函数简单地遍历实例对象的原型(prototype)链(第一个操作数)并比较内部[[proto]]
每个对象的属性到 prototype
构造函数的属性(第二个操作数)。如果它们匹配,则返回 true
;否则,如果原型(prototype)链结束,则返回 false
.
关于JavaScript 继承和构造函数属性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8093057/