提问人:Stefano Borini 提问时间:5/3/2009 最后编辑:MachavityStefano Borini 更新时间:12/12/2022 访问量:81418
基于原型的继承 VS基于类的.class继承
prototype based vs. class based inheritance
问:
在 JavaScript 中,每个对象同时是一个实例和一个类。要进行继承,您可以使用任何对象实例作为原型。
在 Python、C++ 等中。有类和实例作为单独的概念。为了进行继承,您必须使用基类创建一个新类,然后可以使用该类生成派生实例。
为什么 JavaScript 会朝着这个方向发展(基于原型的面向对象)?与传统的基于类的OO相比,基于原型的OO有哪些优点(和缺点)?
答:
这里有大约一百个术语问题,主要是围绕着某人(不是你)试图让他们的想法听起来像最好的。
所有面向对象的语言都需要能够处理几个概念:
- 封装数据以及对数据的关联操作,这些操作通常称为数据成员和成员函数,或数据和方法等。
- 继承,能够说这些对象就像其他对象集一样,除了这些变化
- 多态性(“多种形状”),其中对象自行决定要运行哪些方法,以便您可以依赖语言来正确路由请求。
现在,就比较而言:
首先是整个“类”与“原型”问题。这个想法最初始于 Simula,其中使用基于类的方法,每个类表示一组共享相同状态空间(读取“可能值”)和相同操作的对象,从而形成一个等价类。如果你回头看一下 Smalltalk,因为你可以打开一个类并添加方法,这实际上与你在 Javascript 中可以做的事情相同。
后来的面向对象语言希望能够使用静态类型检查,所以我们得到了在编译时设置固定类的概念。在公开课版本中,您拥有更大的灵活性;在较新的版本中,您可以在编译器中检查某些类型的正确性,否则这些正确性将需要测试。
在“基于类”的语言中,复制发生在编译时。在原型语言中,操作存储在原型数据结构中,该数据结构在运行时被复制和修改。但是,抽象地讲,类仍然是共享相同状态空间和方法的所有对象的等价类。当您将方法添加到原型中时,您实际上是在制作新的等价类的元素。
现在,为什么要这样做?主要是因为它在运行时提供了一种简单、合乎逻辑、优雅的机制。现在,要创建一个新对象或创建一个新类,您只需执行深度复制,复制所有数据和原型数据结构。然后,你或多或少地免费获得继承和多态性:方法查找总是包括按名称向字典询问方法实现。
最终出现在 Javascript/ECMA 脚本中的原因基本上是,当我们在 10 年前开始使用它时,我们处理的是功能不那么强大的计算机和不太复杂的浏览器。选择基于原型的方法意味着解释器可以非常简单,同时保留面向对象的理想属性。
评论
你应该看看 Douglas Crockford 写的一本关于 JavaScript 的好书。它很好地解释了 JavaScript 创建者做出的一些设计决策。
JavaScript 的一个重要设计方面是它的原型继承系统。对象在 JavaScript 中是一等公民,以至于常规函数也被实现为对象(准确地说是“函数”对象)。在我看来,当它最初被设计为在浏览器中运行时,它旨在用于创建大量单例对象。在浏览器 DOM 中,您会发现该窗口、文档等都是单例对象。此外,JavaScript 是松散类型的动态语言(与强类型的 Python 相反,动态语言),因此,通过使用“原型”属性实现了对象扩展的概念。
所以我认为在 JavaScript 中实现的基于原型的 OO 有一些优点:
- 适用于松散类型的环境,无需定义显式类型。
- 使实现单例模式变得非常容易(在这方面比较 JavaScript 和 Java,你就会知道我在说什么)。
- 提供在不同对象的上下文中应用对象的方法、从对象动态添加和替换方法的方法等(这在强类型语言中是不可能的)。
以下是原型OO的一些缺点:
- 没有实现私有变量的简单方法。使用 Crockford 的魔法和闭包实现私有变量是可能的,但它绝对不像在 Java 或 C# 中使用私有变量那样简单。
- 我还不知道如何在 JavaScript 中实现多重继承(它的价值)。
评论
在《自我:简单的力量》一文中可以找到略微偏向于基于原型的方法的比较。本文提出了以下支持原型的论点:
Creation by copying. Creating new objects from prototypes is accomplished by a simple operation, copying, with a simple biological metaphor, cloning. Creating new objects from classes is accomplished by instantiation, which includes the interpretation of format information in a class. Instantiation is similar to building a house from a plan. Copying appeals to us as a simpler metaphor than instantiation.
Examples of preexisting modules. Prototypes are more concrete than classes because they are examples of objects rather than descriptions of format and initialization. These examples may help users to reuse modules by making them easier to understand. A prototype-based system allows the user to examine a typical representative rather than requiring him to make sense out of its description.
Support for one-of-a-kind objects. Self provides a framework that can easily include one-of-a-kind objects with their own behavior. Since each object has named slots, and slots can hold state or behavior, any object can have unique slots or behavior. Class-based systems are designed for situations where there are many objects with the same behavior. There is no linguistic support for an object to possess its own unique behavior, and it is awkward to create a class that is guaranteed to have only one instance [think singleton pattern]. Self suffers from neither of these disadvantages. Any object can be customized with its own behavior. A unique object can hold the unique behavior, and a separate "instance" is not needed.
Elimination of meta-regress. No object in a class-based system can be self-sufficient; another object (its class) is needed to express its structure and behavior. This leads to a conceptually infinite meta-regress: a is an instance of class , which is an instance of metaclass , which is an instance of metametaclass , ad infinitum. On the other hand, in prototype-based systems an object can include its own behavior; no other object is needed to breathe life into it. Prototypes eliminate meta-regress.
point
Point
Point
Point
Self is probably the first language to implement prototypes (it also pioneered other interesting technologies like JIT, which later made its way into the JVM), so reading the other Self papers should also be instructive.
评论
point
Point
standard-class
The difference between mainstream OOP class-based languages such as c# or java and prototype bases languages such as javascript is the ability to modify object types at runtime whilst in c# or java they gave up this ability in favor of static type checking by making classes fixed at compile time. JS has always been closer to the first original design of OOP of alan Kay and languages such as Smalltalk or simula.
this is achieved by making the blueprint itself an instance, types in prototype-based are actual instances that can be accessed and modified at runtime, in Javascript this is really easy using the prototype object, since every object type has this object.
example: type funcName.prototype.myNewMethod= function{ console.log("hello world")}
评论
GEB