JavaScript是一种基于原型的语言,这意味着什么?

282
据说JavaScript的一个主要优点是它是一种基于原型的语言。但是什么是基于原型,为什么这是一个优点呢?

3
这个回答详细解释了原型继承的一切:https://dev59.com/GXE85IYBdhLWcg3wYigB#16872315 - Aadit M Shah
8个回答

322

原型继承是面向对象编程中的一种代码重用形式。JavaScript是少数采用原型继承方式的主流面向对象语言之一,其他大部分面向对象语言都是经典继承。

经典继承中,程序员编写一个类来定义一个对象,同一类别的多个对象可以从同一个类中实例化,因此您可以在一个地方编写描述程序中多个对象的代码。类别可以组织成层次结构,进一步提高代码的重用性。通用代码存储在较高层次的类别中,以便从低级别类别继承。这意味着一个对象与同一类别的其他对象以及其父类共享代码。

原型继承中,对象直接从其他对象继承。所有关于类的业务都消失了。如果要创建一个对象,只需要编写一个对象即可。但是代码重用仍然是有价值的,因此允许将对象链接在层次结构中。在JavaScript中,每个对象都有一个指向创建它的对象的秘密链接,形成一个链。当请求一个对象没有的属性时,会向上沿着链询问其父对象...直到找到该属性或者到达根对象为止。

JavaScript中的每个函数(它们本身也是对象)实际上都有一个名为“prototype”的成员,该成员负责在请求一个对象的值时提供值。拥有这个成员可以使构造函数机制(通过该机制使用函数构造对象)工作。向函数对象的原型添加属性将使其对于构造出的对象和继承自它的所有对象都可用。

优点

为什么原型继承是一种有利的代码重用形式可能没有硬性规定。代码重用本身就是有利的,而原型继承是一个明智的选择。你可能会认为原型继承是一种相当简单的代码重用模型,代码可以通过直接方式大量重用。但传统语言当然也能够做到这一点。

附注:@Andrew Hedges 指出,实际上有许多基于原型的编程语言。(参见链接)这些语言的存在值得注意,但也值得注意的是,它们中没有一种是流行的。NewtonScript 似乎曾经有一些影响力,但随着平台的消失而消亡。还可以通过扩展一些现代语言的方式,添加原型功能。


10
嗨,Kelly。虽然JavaScript是迄今为止最流行的原型语言,但还有许多其他语言:http://en.wikipedia.org/wiki/Prototype-based_programming#Languages - Andrew Hedges
2
嘿,安德鲁。说得好。我应该更清楚地表达。我会做个记录的。 - keparo
5
好的,我会尽力进行翻译并保持原文意思的准确性。以下是需要翻译的内容:请也阅读这个链接:https://developer.mozilla.org/en/JavaScript/Guide/Details_of_the_Object_Model - pramodc84
1
对于一个很好的答案点赞。一个小评论:对我来说,经典继承似乎比原型继承更“直接”。实际上,我认为原型对象只是链接(到其他对象),而在编译的面向对象编程中,我认为基类是“直接继承”的。因此,原型对象是链接在一起而不是继承的(继承有点虚假)。有什么想法吗? - Prisoner ZERO
5
@PrisonerZERO:我认为原型继承比经典继承更直接。不同于对象B指向从对象A所指的类继承而来的类,它直接指向对象A并说:“我就像那个对象,只是...”。关于原型继承最重要的一点,并且似乎对大多数人来说最难以内化的是它不区分实例和类型。每个对象既是类型又是实例。将两者区分开来是人为的和有意为之的,通常是陷入面向类思维方式的症状。 - cHao

60

一种基于原型的语言不区分类和对象:它只有对象。一个基于原型的语言具有原型对象的概念,这是一个用作模板的对象,从中获取新对象的初始属性。任何对象都可以在创建时或运行时指定自己的属性。此外,任何对象都可以关联为另一个对象的原型,使得第二个对象共享第一个对象的属性。


6
解释很好,但对于“用于初始属性的模板”一词的评论有些误导。如果在实例化对象后更改原型,该对象仍会接收这些函数。 - nickf

39

基于原型(Prototype-based)的编程是一种面向对象编程风格,其中没有类,而是通过克隆充当原型的现有对象来实现行为复用(或在基于类的语言中实现继承)。


你还有这种感觉吗?如果是的话,那么这是第一个真正让我完全“恍然大悟”的解释。 - Chazt3n

11
优点/缺点是,我们可以在运行时创建新的对象,而不需要定义类(静态代码)。与大多数功能一样,开发人员可以将其转化为优势/劣势。
这是可能的,因为在JavaScript中对象本质上是函数(闭包也是如此)。

动态对象是JavaScript的一个好处,但它们并不真正与JavaScript作为原型或函数式语言有关。在许多经典语言中,您可以在运行时创建动态对象。闭包有些无关紧要。 - keparo
2
类不一定是静态代码 - 看看Python,其中类本身就是对象,并且由元类构建而成,这些元类也是对象。 - Tomasz Zieliński

8
阅读所有答案后,得出以下结论:
1) 面向对象编程的继承是通过直接从其他对象中继承而来的
2) 不使用类
3) 也称为基于实例的编程或无类原型导向编程
4) 行为重复利用是通过克隆现有对象作为原型来完成的
5) 从新对象获取初始属性的对象被用作模板

7

不需要声明一个类结构,你可以创建相同类型的对象,并且随时使用对象的原型来添加到它们的定义中。这比通常的做法更加灵活。


6

如果您仅在运行时使用对象而不是在编译时使用类来构建新对象,则可以扩展对象而无需了解任何详细信息。当然,这取决于使用方式,很快可能会变成一个劣势。我在此不对语言做任何假设,因此适用于其他不太动态的语言,而不仅仅是javascript。

myobject.prototype=unkownobject;
myobject.newproperty=1;

您可以从任何地方获取对象:您自己的代码、网络、数据库、外部链接等等。
请注意,一种语言不必像JavaScript那样实现原型继承。在JavaScript中,原型对象仅仅是共享的,它的属性也是如此,在继承者之间。另一种选择是将原型的所有属性复制到新对象中。每种方法在不同情况下都有其优点。我更喜欢第二种方法,但这并不是JavaScript所做的。

0

JavaScript的原型继承具有内存保护的优势。在像Java这样的语言中,对象会生成它们自己的超类实例变量和方法的副本,而在JS中,“super”对象为每个从它继承的“sub”对象提供访问其变量和方法的途径,而无需重新创建它们。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接