在JavaScript中,每个对象都是实例和类。要进行继承,可以使用任何对象实例作为原型。
在Python,C ++等中。有类和实例作为单独的概念。为了进行继承,您必须使用基类来创建一个新类,然后可以使用它来生成派生实例。
为什么JavaScript会朝这个方向发展(基于原型的面向对象)?基于原型的OO相对于传统的,基于类的OO有哪些优点(和缺点)?
答案 0 :(得分:186)
这里有大约一百个术语问题,主要围绕某人(不是你)试图让他们的想法听起来像The Best。
所有面向对象的语言都需要能够处理几个概念:
现在,就比较而言:
首先是整个“阶级”与“原型”问题。这个想法最初开始于Simula,其中使用基于类的方法,每个类表示一组共享相同状态空间(读取“可能值”)和相同操作的对象,从而形成等价类。如果你回顾一下Smalltalk,因为你可以打开一个类并添加方法,这实际上与你在Javascript中可以做的一样。
后来的OO语言希望能够使用静态类型检查,因此我们在编译时获得了固定类集的概念。在开放阶段版本中,您具有更大的灵活性;在较新的版本中,您可以检查编译器中的某些正确性,否则需要进行测试。
在“基于类”的语言中,复制发生在编译时。在原型语言中,操作存储在原型数据结构中,在运行时复制和修改。但是,抽象地说,类仍然是共享相同状态空间和方法的所有对象的等价类。当您向原型添加方法时,您将有效地创建新等价类的元素。
现在,为什么这样做?主要是因为它在运行时创建了一个简单,合理,优雅的机制。现在,要创建一个新对象或来创建一个新类,您只需执行深层复制,复制所有数据和原型数据结构。您可以或多或少地免费获得继承和多态性:方法查找始终包括通过名称向字典询问方法实现。
最终出现在Javascript / ECMA脚本中的原因基本上就是当我们10年前开始使用它时,我们处理的是功能较弱的计算机和不太复杂的浏览器。选择基于原型的方法意味着解释器可以非常简单,同时保留面向对象的理想属性。
答案 1 :(得分:37)
可以在论文中找到比较,即略微偏向基于原型的方法 - Self: The power of simplicity。本文提出以下论据支持原型:
通过复制创建。从原型创建新对象是通过 一个简单的操作,复制,用简单的生物学比喻,克隆。创建 来自类的新对象是通过实例化完成的,其中包括 解释类中的格式信息。实例化是 类似于从计划中建造房屋。复制呼吁我们作为一个更简单的比喻 比实例化。
预先存在的模块的示例。原型比类更具体 因为它们是对象的示例,而不是格式和初始化的描述。 这些示例可以帮助用户更轻松地重用模块 了解。基于原型的系统允许用户检查典型代表 而不是要求他理解其描述。
支持独一无二的对象。 Self提供了一个可以轻松实现的框架 包括具有自己行为的独一无二的对象。因为每个对象都有 命名槽,槽可以保持状态或行为,任何对象都可以有唯一的槽 或行为。基于类的系统设计用于以下情况 有许多具有相同行为的对象。没有语言支持 对象拥有自己独特的行为,并且创建一个保证只有一个实例的类是很尴尬的(认为Singleton模式)。自我也没有这些缺点。 可以使用自己的行为自定义任何对象。一个独特的对象可以 保持独特的行为,不需要单独的“实例”。
消除元退步。基于类的系统中的任何对象都不能自给自足;
需要另一个对象(它的类)来表达它的结构和行为。
这导致概念上无限的元回归:point
是类的实例
Point
,它是元类Point
的一个实例,它是metametaclass的一个实例
Point
,无限。另一方面,在基于原型的系统中有一个对象
可以包括自己的行为;没有其他目标需要为其注入生命。原型
消除元回归。
Self可能是第一种实现原型的语言。 (它还开创了其他有趣的技术,如JIT,后来进入JVM。所以阅读the other Self papers也应该是有益的。
答案 2 :(得分:22)
您应该great book on JavaScript查看Douglas Crockford。它为JavaScript创建者所做的一些设计决策提供了非常好的解释。
JavaScript的一个重要设计方面是其原型继承系统。对象是JavaScript中的一等公民,以及常规函数也被实现为对象('Function'对象是精确的)。在我看来,当它最初设计为在浏览器中运行时,它意味着用于创建大量的单例对象。在浏览器DOM中,您可以找到窗口,文档等所有单例对象。此外,JavaScript是松散类型的动态语言(而不是强类型的动态语言Python),因此,通过使用'prototype'属性实现了对象扩展的概念。
所以我认为在JavaScript中实现了基于原型的OO的一些优点: