关于javascript:基于原型和基于类的继承

prototype based vs. class based inheritance

在JavaScript中,每个对象同时是一个实例和一个类。要进行继承,可以将任何对象实例用作原型。

在Python,C++等。有类和实例作为单独的概念。为了进行继承,必须使用基类创建一个新的类,然后才能使用该类生成派生实例。

为什么JavaScript会朝这个方向发展(基于原型的对象方向)?与传统的基于类的OO相比,基于原型的OO有哪些优点(和缺点)?


这里有大约一百个术语问题,主要围绕着某人(而不是你),试图让他们的想法听起来像是最好的。

所有面向对象的语言都需要能够处理几个概念:

  • 对数据的封装以及对数据的相关操作,这些操作有各种各样的名称,如数据成员和成员函数,或者作为数据和方法等等。
  • 继承,表示这些对象与其他对象集一样的能力,除了这些更改
  • 多态性("许多形状"),其中一个对象本身决定运行什么方法,以便您可以依赖语言来正确地路由请求。
  • 现在,就比较而言:

    首先是整个"类"和"原型"问题。这个想法最初是从Simulat开始的,在Simulat中,使用基于类的方法,每个类表示一组共享相同状态空间(读取"可能值")和相同操作的对象,从而形成一个等价类。如果回顾smalltalk,因为您可以打开一个类并添加方法,这实际上与您在javascript中所做的相同。

    后来OO语言希望能够使用静态类型检查,所以我们在编译时得到了固定类集的概念。在开放类版本中,您有更多的灵活性;在较新的版本中,您有能力在编译器中检查某些类型的正确性,否则将需要进行测试。

    在"基于类的"语言中,复制是在编译时进行的。在原型语言中,操作存储在原型数据结构中,该结构在运行时进行复制和修改。然而,抽象地说,类仍然是共享相同状态空间和方法的所有对象的等价类。当您向原型添加一个方法时,实际上是在生成一个新等价类的元素。

    现在,为什么要这样做?主要是因为它在运行时提供了一个简单、逻辑、优雅的机制。现在,要创建一个新对象,或者创建一个新类,只需执行一个深度复制,复制所有数据和原型数据结构。您可以免费获得继承和多态性:方法查找通常包括按名称向字典请求方法实现。

    最终出现在javascript/ecma脚本中的原因基本上是,当我们10年前开始使用这个脚本时,我们正在处理的是功能弱得多的计算机和复杂得多的浏览器。选择基于原型的方法意味着解释器可以非常简单,同时保持对象方向的理想属性。


    一个稍微偏向于基于原型的方法的比较,可以在本文中找到——自我:简单的力量。本文提出了以下有利于原型的论点:

    通过复制创建。从原型创建新对象是由一个简单的操作,复制,用一个简单的生物学比喻,克隆。创建类中的新对象通过实例化完成,其中包括一个类中格式信息的解释。实例化是类似于从平面图上建造房屋。抄袭对我们来说是一个简单的比喻而不是实例化。

    先前存在的模块示例。原型比类更具体因为它们是对象的例子,而不是格式和初始化的描述。这些示例可以帮助用户更容易地重用模块。理解。基于原型的系统允许用户检查典型代表而不是要求他从描述中理解。

    支持独一无二的对象。Self提供了一个框架,可以轻松地将一种类型的对象包括在它们自己的行为中。因为每个对象命名槽,槽可以保持状态或行为,任何对象都可以有唯一的槽或行为。基于类的系统设计用于有许多对象具有相同的行为。没有语言支持对象拥有自己独特的行为,而创建一个保证只有一个实例的类是很尴尬的(想想单例模式)。自我不受这些不利因素的影响。任何对象都可以用自己的行为进行定制。唯一的对象可以保持唯一的行为,不需要单独的"实例"。

    消除元回归。在基于类的系统中,没有对象是自给自足的;需要另一个对象(它的类)来表示它的结构和行为。这导致概念上无限的元回归:point是类的一个实例。point是元类point的一个实例,是元类的一个实例。point,无限大。另一方面,在基于原型的系统中,对象可以包括它自己的行为;不需要其他物体来向它呼吸生命。原型消除元回归。

    Self可能是实现原型的第一种语言。(它还开创了其他有趣的技术,如JIT,后来它进入了JVM。所以阅读其他的自我论文也应该是有指导意义的)。


    你应该看看道格拉斯·克罗克福德的一本关于javascript的好书。它对JavaScript创建者所做的一些设计决策提供了非常好的解释。

    Javascript的一个重要设计方面是它的原型继承系统。对象是JavaScript中的头等公民,所以常规函数也作为对象实现("函数"对象更精确)。在我看来,当它最初设计为在浏览器中运行时,它是用来创建许多单例对象的。在浏览器DOM中,您可以找到该窗口、文档等所有单例对象。另外,JavaScript是松散类型的动态语言(与强类型的动态语言python相反),因此,通过使用"原型"属性实现了对象扩展的概念。

    因此,我认为在JavaScript中实现的基于原型的OO有一些优点:

  • 适用于松散类型的环境,无需定义显式类型。
  • 实现简单的模式非常简单(在这方面比较JavaScript和Java,你就会知道我在说什么)。
  • 提供在不同对象的上下文中应用对象方法、从对象动态添加和替换方法等(强类型语言中不可能实现的内容)的方法。
  • 以下是原型OO的一些缺点:

  • 实现私有变量并非易事。使用CROROFROD的巫术使用闭包是可能实现私有VARS的,但是它绝对不象使用Java或C语言中的私有变量那么简单。
  • 我还不知道如何在JavaScript中实现多个继承(为了它的价值)。