我理解你的问题。您提到的幻灯片 - John Resig 的第 76 张幻灯片,已在以下答案中进行了解释:
https://stackoverflow.com/a/17768570/783743
您的问题是人们第一次学习 JavaScript 时遇到的经典问题;这个问题的出现不是因为你不理解原型继承,而是因为原型继承在 JavaScript 中的描述方式。
原型继承的两个方面
原型继承可以通过两种方式之一来实现。因此原型继承类似于硬币。它有两个面孔:
- 原型继承的原型模式
- 原型继承的构造函数模式
第一种模式是原型继承的常见或真实模式。像 Self 和 Lua 这样的语言采用原型继承的原型模式。
第二种模式旨在使原型继承看起来像经典继承。它仅在 JavaScript 中使用,它隐藏了原型继承的工作方式,使其难以理解。
我在关于原型继承为何重要的文章中深入讨论了原型继承,我建议您仔细阅读。
了解原型继承
原型继承是关于从其他对象继承的对象。原型继承中没有类。只有对象。例如,考虑:
var boy = {};
var bob = Object.create(boy);
在上面的示例中,对象bob
继承自 object boy
。用简单的英语:
鲍勃是个男孩。
在经典继承中,您可以将上述内容编写为:
class Boy {
// body
}
Boy bob = new Boy;
如您所见,原型继承非常灵活。在原型继承中,您需要的只是对象。对象既是类又是实例。表现为类的对象称为原型。因此boy
是 的原型bob
。
从原型构造对象
现在考虑我们有一个名为 的对象rectangle
:
var rectangle = {
width: 10,
height: 5,
area: function () {
return this.width * this.height;
}
};
我们可以使用rectangle
如下实例:
console.log(rectangle.area());
另一方面,我们也可以rectangle
用作原型:
var rect2 = Object.create(rectangle);
rect2.width = 15;
rect2.height = 6;
console.log(rect2.area());
然而width
,height
在每个继承自rectangle
. 因此我们创建了一个构造函数:
rectangle.create = function (width, height) {
var rect = Object.create(this);
rect.height = height;
rect.width = width;
return rect;
};
现在您可以创建rectangle
如下实例:
var rect2 = rectangle.create(15, 6);
console.log(rect2.area());
这是原型继承的原型模式,因为在这种方法中,重点是原型而不是构造函数create
。
构造函数模式
同样的事情可以在 JavaScript 中使用构造函数模式来完成,如下所示:
function Rectangle(width, height) {
this.height = height;
this.width = width;
}
var rectangle = Rectangle.prototype;
rectangle.width = 10;
rectangle.height = 5;
rectangle.area = function () {
return this.width * this.height;
};
var rect2 = new Rectangle(15, 6);
console.log(rect2.area());
构造函数模式的问题在于,重点是构造函数而不是原型。因此,人们认为这rect2
是一个Rectangle
错误的例子。在 JavaScript 中,对象继承自其他对象而不是构造函数。
该对象是创建时的rect2
一个实例。它不是.Rectangle.prototype
rect2
Rectangle
你的问题
在您的问题中,您定义Foo
如下:
var Foo = function() {
this.report('Foo');
};
Foo.report = function(i) {
alert('report: ' + i);
};
Foo
因此,当您使用new
(即)创建对象时,new Foo
该对象继承自Foo.prototype
. 它不继承自Foo
. 因此,该对象没有调用任何属性report
,因此会引发错误。
在您的问题中,您还定义Bar
:
var Bar = function() {
this.report('Bar');
};
Bar.prototype = Foo; // Right; it's not 'new Foo()'
这里prototype
是。Bar
_ Foo
因此,从创建的对象Bar
将继承自Bar.prototype
or Foo
。因此,这些对象report
从Foo
.
我知道。这很令人困惑,但这就是在 JavaScript 中实现原型继承的方式。不要忘记阅读我的博文:
为什么原型继承很重要