这让很多人感到困惑,因为JavaScript使用了一种非常不同的继承和类的概念。在JavaScript中,包括类在内的
所有内容都是对象。构成
类部分的所有方法等都包含在一个名为
prototype
的对象中。其中的一部分是一个名为
init
的函数。当你执行
new Foo()
时,你正在构造一个新对象,并且一些
init
方法将适当的内容(包括原型)复制到该新对象中。
因此,当您通过以下方式向
prototype
添加函数时:
myClass.prototype.example1 = function(){}
实际上,您正在向类添加一个新方法,然后在您构造的myClass的任何实例中继承该方法。而在第二种情况下,
myClass.example2 = function(){}
您只需将新方法添加到原始myClass对象中。在Java术语中,这基本上是将其更改为新类型对象,该对象的行为与myClass完全相同,除了它现在具有一个example2()
方法。
更新
另一个答案提到了Crockford的经典继承笔记。我建议也阅读原型继承文章。
另一个更新
好的,让我们倒退一步。首先,什么是对象?基本上,它是一种结构,结合了状态和行为。
我们有一个具有添加方法的Number的想法,并且我们有一种称为Integer的Number类型,它“行为类似”于Number,但仅限于特定范围内的值。在像Java这样的语言中,您可能会有
abstract class Number {
public void addTo(Number arg);
}
然后
class Integer extends Number {
int val;
public void addTo(Integer arg){ val += arg; }
}
(不要为Java的细节烦扰我,我只是想表达一个观点。)
你所说的是,可能有许多对象都是数字,并且它们都有一个名为“addTo”的行为。在数学上,由共同属性标识的事物集合有时被称为“等价类”,这就是我们得到“类”的名称的方式。
我们还确定了一种特殊类型的数字,叫做整数,其取值范围有限,在-32767和32768之间。(测验:为什么是这些值?)但是,它在任何方面都像数字一样:你也可以将整数添加到其中。这个语句“在每个方面的行为类似——但有这些限制”通常缩写为“是一个”,这就是我们所说的“继承”。
所以现在你可以写了。
Integer a, b;
// they get initial values somehow, left as an exercise
a.addTo(b);
并且编译器会找到
对象a
,找到它特定的行为
addTo
,并知道如何连接一切以使其正常工作。有时候,比如在早期版本的C++中,这必须在编译时完成;在后来的C++和Java中,也有一种方法可以在运行时进行连接(“延迟绑定”),基本上就是在某个地方拥有一个表格,其中说:
如果我有一个整数,我需要一个addTo方法,这里是它的地址;使用它。
Javascript和一些之前的语言(如Self)做法略有不同。现在,一个对象只是包含......东西的结构体。其中一些东西可能是数据,一些可能是函数。"类"的概念可以完全抽象出来;"类"只是具有完全相同内容的所有对象的集合。因此,在Javascript中,我们可以像这样制作我们的"Integer"类。
var Integer = {
int val,
addTo : function(b){ val += b ; }
}
(不用担心完全正确的javascript代码,重点是解释概念。)
如果我们复制这个名为Integer
的对象,例如复制到Integer2
中,那么两者都包含一个名为val
和一个名为addTo
的函数。 我们可以说它们都“属于同一类”,因为它们具有完全相同的状态和方法。
问题是,我们如何实现这种复制? 你可以逐位运行整个对象,但这会导致其他问题,所以我们在每个javascript对象的内容中定义了一个特殊对象,名为prototype
,并将所有方法和内容 - 我们想要复制以构建另一个同类对象的所有内容 - 放在其中。 现在我们会得到像这样的东西
var Integer = {
prototype : {
int val,
addTo : function(b){ val += b; }
}
}
我们在语言中添加了一个运算符
new
,它基本上只是复制原型对象。当我们编写以下内容时:
var a = new Integer();
a
现在是一个具有与所有其他Integer
对象相同原型的对象。当我们编写
a.addTo(b);
所有解释器需要做的就是查找包含在
a
中的
prototype
对象并找到其名为
addTo
的方法。为什么要这样做呢?因为现在编译类、添加语法以及确定何时在编译时或运行时绑定,再加上管理运行时表等所有复杂性都转化为两个简单操作:知道如何制作
深拷贝prototype
和如何按名称在
prototype
中查找某些内容。第二种方法是“原型继承”。
var helper = function()
需要改为this.helper = function()
。 - onteria_