原型继承优于经典的好处?

Pie*_*ten 264 javascript oop inheritance language-design prototype-programming

所以这些年来我终于停止了我的脚,并决定"正确"学习JavaScript.语言设计中最令人头疼的元素之一是它的继承实现.有Ruby经验,我很高兴看到闭包和动态打字; 但是对于我的生活来说,无法弄清楚使用其他实例进行继承的对象实例会带来什么好处.

Aad*_*hah 537

我知道这个答案已经晚了3年但我真的认为目前的答案并没有提供关于原型继承如何比经典继承更好的足够信息.

首先让我们看看JavaScript程序员在保护原型继承时所说的最常见的参数(我从当前的答案池中获取这些参数):

  1. 这很简单.
  2. 它很强大.
  3. 它导致更小,更少冗余的代码.
  4. 它是动态的,因此对动态语言更好.

现在这些论点都是有效的,但是没有人为解释原因而烦恼.这就像告诉孩子学习数学很重要.当然可以,但孩子肯定不在乎; 而且你不能说像数学这样的孩子说这很重要.

我认为原型继承的问题在于它是从JavaScript的角度来解释的.我喜欢JavaScript,但JavaScript中的原型继承是错误的.与经典继承不同,有两种原型继承模式:

  1. 原型继承的原型模式.
  2. 原型继承的构造函数模式.

不幸的是,JavaScript使用原型继承的构造函数模式.这是因为在创建JavaScript时,Brendan Eich(JS的创建者)希望它看起来像Java(具有经典继承):

我们把它当作Java的小弟弟推动它,因为像Visual Basic这样的补充语言当时是微软语言家族的C++.

这很糟糕,因为当人们在JavaScript中使用构造函数时,他们会想到从其他构造函数继承的构造函数.这是错的.在原型继承中,对象继承自其他对象.构造函数永远不会出现.这让大多数人感到困惑.

来自像Java这样具有经典继承的语言的人变得更加困惑,因为尽管构造函数看起来像类,但它们的行为并不像类.正如道格拉斯·克罗克福德所说:

这种间接性旨在使语言对于经过专业训练的程序员来说更为熟悉,但却没有做到这一点,正如我们从Java程序员对JavaScript的非常低级的看法中看到的那样.JavaScript的构造函数模式并没有吸引经典人群.它还掩盖了JavaScript真正的原型性质.因此,很少有程序员知道如何有效地使用该语言.

你有它.直接从马的嘴里.

真正的原型继承

原型继承完全是关于对象的.对象从其他对象继承属性.这里的所有都是它的.有两种使用原型继承创建对象的方法:

  1. 创建一个全新的对象.
  2. 克隆现有对象并对其进行扩展.

注意: JavaScript提供了两种克隆对象的方法 - 委托连接.从此以后,我将使用"clone"一词专门通过委托来引用继承,而单词"copy"则通过连接专门引用继承.

足够的谈话.我们来看一些例子.说我有一个半径圆5:

var circle = {
    radius: 5
};
Run Code Online (Sandbox Code Playgroud)

我们可以从半径计算圆的面积和周长:

circle.area = function () {
    var radius = this.radius;
    return Math.PI * radius * radius;
};

circle.circumference = function () {
    return 2 * Math.PI * this.radius;
};
Run Code Online (Sandbox Code Playgroud)

现在我想创建另一个半径圆10.一种方法是:

var circle2 = {
    radius: 10,
    area: circle.area,
    circumference: circle.circumference
};
Run Code Online (Sandbox Code Playgroud)

但JavaScript提供了一种更好的方式 - 委派.Crockford的Object.create功能用于执行此操作:

var circle2 = Object.create(circle);
circle2.radius = 10;
Run Code Online (Sandbox Code Playgroud)

就这样.您刚刚在JavaScript中进行了原型继承.那不简单吗?你拿一个物体,克隆它,改变你需要的东西,然后嘿嘿 - 你得到了一个全新的物体.

现在你可能会问,"这怎么这么简单?每次我想要创建一个新的圆圈,我需要克隆circle并手动为它指定半径".那么解决方案就是使用一个函数为你做繁重的工作:

function createCircle(radius) {
    var newCircle = Object.create(circle);
    newCircle.radius = radius;
    return newCircle;
}

var circle2 = createCircle(10);
Run Code Online (Sandbox Code Playgroud)

实际上,您可以将所有这些组合成一个对象文字,如下所示:

var circle = {
    radius: 5,
    create: function (radius) {
        var circle = Object.create(this);
        circle.radius = radius;
        return circle;
    },
    area: function () {
        var radius = this.radius;
        return Math.PI * radius * radius;
    },
    circumference: function () {
        return 2 * Math.PI * this.radius;
    }
};

var circle2 = circle.create(10);
Run Code Online (Sandbox Code Playgroud)

JavaScript中的原型继承

如果您在上面的程序中注意到该create函数创建了一个克隆circle,为radius它分配一个新的,然后返回它.这正是构造函数在JavaScript中的作用:

function Circle(radius) {
    this.radius = radius;
}

Circle.prototype.area = function () {
    var radius = this.radius;
    return Math.PI * radius * radius;
};

Circle.prototype.circumference = function () {         
    return 2 * Math.PI * this.radius;
};

var circle = new Circle(5);
var circle2 = new Circle(10);
Run Code Online (Sandbox Code Playgroud)

JavaScript中的构造函数模式是反转的原型模式.您可以创建构造函数,而不是创建对象.的new关键字结合this构造内部指针的一个克隆prototype的构造的.

听起来很混乱?这是因为JavaScript中的构造函数模式不必要地使事情复杂化.这是大多数程序员难以理解的.

他们没有考虑从其他对象继承的对象,而是认为构造函数继承自其他构造函数,然后变得完全混淆.

还有很多其他原因可以避免JavaScript中的构造函数模式.您可以在我的博客文章中阅读它们:构造函数与原型


那么原型继承优于经典继承有什么好处呢?让我们再次讨论最常见的论点,并解释原因.

1.原型继承很简单

CMS在他的回答中说:

在我看来,原型继承的主要好处是它的简单性.

让我们考虑一下我们刚刚做了什么.我们创建了circle一个半径为的对象5.然后我们克隆它并给克隆半径为10.

因此,我们只需要两件事就可以使原型继承工作:

  1. 一种创建新对象的方法(例如,对象文字).
  2. 一种扩展现有对象的方法(例如Object.create).

相比之下,经典继承要复杂得多.在经典继承中,你有:

  1. 类.
  2. 宾语.
  3. 接口.
  4. 抽象类.
  5. 最后的课程.
  6. 虚拟基类.
  7. 构造函数.
  8. 析构函数.

你明白了.关键是原型继承更容易理解,更容易实现,更容易推理.

正如Steve Yegge在他的经典博客文章" N00b的肖像 "中所说:

元数据是任何其他类型的描述或模型.代码中的注释只是计算的自然语言描述.元数据元数据的原因在于它并非绝对必要.如果我有一条带有一些谱系文书的狗,而我丢失了文书工作,我仍然有一只完全有效的狗.

在同样的意义上,类只是元数据.继承不严格要求类.然而,有些人(通常是n00bs)找到更舒适的课程.它给了他们一种虚假的安全感.

好吧,我们也知道静态类型只是元数据.它们是针对两种读者的专门评论:程序员和编译器.静态类型讲述了有关计算的故事,可能是为了帮助两个读者组理解程序的意图.但是静态类型可以在运行时抛弃,因为最终它们只是风格化的注释.他们就像是谱系文书工作:它可能会使某种不安全的性格类型对他们的狗更开心,但狗肯定不会在意.

正如我之前所说,课程给人一种虚假的安全感.例如NullPointerException,即使您的代码非常清晰,您在Java中也会得到太多.我发现经典继承通常会妨碍编程,但也许只是Java.Python有一个惊人的经典继承系统.

2.原型继承是强大的

大多数来自古典背景的程序员认为经典继承比原型继承更强大,因为它具有:

  1. 私有变量.
  2. 多重继承.

这种说法是错误的.我们已经知道JavaScript 通过闭包支持私有变量,但是多重继承呢?JavaScript中的对象只有一个原型.

事实是原型继承支持从多个原型继承.原型继承只是意味着一个对象继承自另一个对象.实际上有两种方法可以实现原型继承:

  1. 委托或差异继承
  2. 克隆或连接继承

是JavaScript只允许对象委托给另一个对象.但是,它允许您复制任意数量的对象的属性.例如_.extend就是这样.

当然,由于许多程序员不认为这是正确的继承instanceofisPrototypeOf别的说法.但是,通过在每个通过串联继承原型的对象上存储原型数组,可以很容易地解决这个问题:

function copyOf(object, prototype) {
    var prototypes = object.prototypes;
    var prototypeOf = Object.isPrototypeOf;
    return prototypes.indexOf(prototype) >= 0 ||
        prototypes.some(prototypeOf, prototype);
}
Run Code Online (Sandbox Code Playgroud)

因此,原型继承与经典继承一样强大.实际上它比经典继承更强大,因为在原型继承中,您可以手动选择要复制的属性以及从不同原型中省略哪些属性.

在经典继承中,选择要继承的属性是不可能的(或者至少是非常困难的).他们使用虚拟基类和接口来解决钻石问题.

然而,在JavaScript中,您很可能永远不会听到钻石问题,因为您可以精确控制要继承的属性以及原型.

3.原型继承不那么冗余

这一点有点难以解释,因为经典继承不一定会导致更多的冗余代码.实际上,继承(无论是经典还是原型)用于减少代码中的冗余.

一个论点可能是大多数具有经典继承的编程语言是静态类型的,并且需要用户显式声明类型(与具有隐式静态类型的Haskell不同).因此,这会导致更详细的代码.

Java因这种行为而臭名昭着.我清楚地记得Bob Nystrom在他关于Pratt Parsers的博客文章中提到了以下轶事:

你必须喜欢Java的"请在一式四份签署"官僚程度.

再说一次,我认为这只是因为Java糟透了.

一个有效的论点是,并非所有具有经典继承的语言都支持多重继承.再次想到Java.是Java有接口,但这还不够.有时你真的需要多重继承.

由于原型继承允许多重继承,因此如果使用原型继承而不是使用具有经典继承但没有多重继承的语言编写,那么需要多继承的代码就不那么多了.

4.原型继承是动态的

原型继承最重要的优点之一是您可以在创建原型后为其添加新属性.这允许您向原型添加新方法,该方法将自动提供给委托给该原型的所有对象.

这在经典继承中是不可能的,因为一旦创建了类,就无法在运行时修改它.这可能是原型继承优于经典继承的最大优势,它应该是最重要的.但是我喜欢最好的保存.

结论

原型继承很重要.让JavaScript程序员了解为什么放弃原型继承的构造函数模式以支持原型继承的原型模式是很重要的.

我们需要开始正确地教授JavaScript,这意味着向新程序员展示如何使用原型模式而不是构造函数模式编写代码.

使用原型模式不仅可以更容易地解释原型继承,而且还可以使更好的程序员.

如果您喜欢这个答案,那么您还应该阅读我的博客文章" 为什么原型继承很重要 ".相信我,你不会失望的.

  • 虽然我理解你的来源,并且我同意原型继承非常有用,但我认为通过假设"原型继承优于经典继承",你已经注定要失败.为了给你一些观点,我的库jTypes是JavaScript的经典继承库.因此,作为一个花时间去做的人,我仍然会坐在这里说原型继承是非常有用的.但它只是程序员所拥有的众多工具之一.原型继承仍有许多缺点. (27认同)
  • 你正在使用单词**clone**,这是完全错误的.`Object.create`正在使用指定的原型创建新对象.您选择的单词给人的印象是原型被克隆. (24认同)
  • 那么这是你的看法,但我会继续不同意,我认为像CoffeeScript和TypeScript这样日益流行的事物表明,有一大群开发人员希望在适当的时候使用这个功能.如你所说,ES6添加了语法糖,但仍然没有提供jTypes的广泛性.在旁注中,我不是那个对你的downvote负责的人.虽然我不同意你的观点,但我认为这并不意味着你的答案很糟糕.你非常彻底. (8认同)
  • @Aadit:真的没必要那么防守.你的答案非常详细,值得投票.我并不是说"链接"应该是"克隆"的替代品,而是它更恰当地描述了一个对象与它继承的原型之间的联系,无论你是否断言你自己的术语"克隆"的定义" 或不.改变它或不改变它,这完全是你的选择. (7认同)
  • 我完全同意你所说的话.我觉得有太多的程序员因为缺乏经典继承而拒绝JavaScript,或者谴责它是一种简单而愚蠢的语言.它实际上是一个非常强大的概念,我同意,许多程序员应该接受并学习它.话虽如此,我也觉得JavaScript中有相当多的开发人员反对任何形式的经典继承,所有这些都是在JavaScript中,当他们根本没有任何依据时.两者在本身同样强大,同样有用. (6认同)
  • 不得不给你一个关于这个的选中标记.非常有争议. (6认同)
  • **克隆**绝对是一个糟糕的选择.克隆被定义为其他东西的精确副本,而不是"constructors"或"Object.create"所发生的情况.没有复制.答案的措辞现在,你冒着造成更多混乱的风险. (4认同)
  • 很好的答案,谢谢.但是,您说:"原型继承最重要的优点之一是您可以在创建原型后为其添加新属性......这在经典继承中是不可能的,因为一旦创建了类,您就无法修改它在运行时." 这可能只是Java糟透了的另一个人工制品.例如,Ruby使用类并允许在运行时修改它们. (4认同)
  • @PavelHoral我用"克隆"这个词来表示缺少一个更好的词.但是我确实区分了委托(链接到原型)和连接(复制原型的属性)之间的区别.我只使用了"clone"这个词来代表委托,而单词"copy"专门用于连接.不过,我会编辑我的答案来解释克隆在这种情况下的含义.你介意删除你的downvote吗?我真的不认为我的答案是值得的,仅仅是因为选择了一个词.如果你能想到一个更好的词,那么我很乐意用这个词取代"克隆". (3认同)
  • "通过在每个对象上存储一系列原型,可以很容易地解决这个问题".现在,您以非标准方式扩展对象,以弥补语言中缺少的功能.而且你正在创建一个总是使用你的新copyOf方法而不是instanceOf和isPrototypeOf的约定,这个约定你必须教给团队中的每个新程序员,以及他们必须传递给你的程序员.这很难看 - javascript根本不是为代码库构建的,这些代码库是由未来几十年的几代人使用和更新的. (3认同)
  • 至于冗余,我认为你高估了这一点。例如,假设我正在浏览您的代码,我看到类似:“ var obj = FactoryOfFactories.makeObjectWith("fire", "ice", "metal") ”。在这种情况下,我完全不知道这个工厂工厂会产生什么类型,只知道它是用火、冰和金属建造的。我不知道它有什么变量。我不知道它有什么方法。我没有办法使用 IDE 来提取它的方法。除非你有非常好的文档,否则我几乎被搞砸了。 (3认同)
  • @redline 重点是 JavaScript 是一种原型语言。不是古典语言。大多数程序员从尝试模仿 [JavaScript 中的经典继承](http://javascript.crockford.com/inheritance.html) 开始,而且 [这样做真的很容易](http://aaditmshah.github.io/standardizing -和谐类/)。然而他们很快意识到真正的原型继承更好(至少在 JavaScript 中)。JavaScript 是最流行的原型语言。不幸的是,它使用构造函数模式而不是原型模式,这使得理解原型继承变得困难。 (2认同)
  • @redline,我不想成为破坏你的泡沫的人,但试图在JavaScript中模仿经典继承是一个非常糟糕的主意.ECMAScript Harmony将有[classes](http://wiki.ecmascript.org/doku.php?id=strawman:maximally_minimal_classes),但它只是构造函数模式的语法糖.另一方面,我看到了你的jTypes库,我认为它完全走向错误的方向.经典继承适用于Java或C++,但尝试在JavaScript中模拟访问修饰符,虚拟类等是一个非常不稳定的解决方案.JavaScript不适用于经典OOP.=) (2认同)
  • @redline,CoffeeScript很受欢迎.TypeScript,不是那么多.祝你好运.祝你好运.我个人觉得添加访问修饰符等,因为jTypes确实是矫枉过正.你真的不需要它在JavaScript中.您的图书馆面向的是一小群程序员,他们来自经典的继承背景.因此我怀疑它会获得多大动力.另一方面,我浏览了你的代码,这非常令人印象深刻.你是一个才华横溢的程序员.我讨厌看到这样的人才浪费.我建议你考虑另一个范围更广的项目.也许写一个博客 - 这有帮助. (2认同)
  • @AaditMShah虽然我喜欢你的第四点.考虑维护几千行多个javascript文件.我们需要在非常文件中查找变量.变量名中的一个小错误会造成严重破坏.编译器没有指出错误.到目前为止,无法使用自动建议或自动更正来编写好的IDE.变量名称无法重构.IDE也不能建议第三方模块的接口.Javascript程序员必须查找其他代码才有意义.Java有jar文件,可以进行内省.静态类型语言具有所有这些优点. (2认同)
  • Javascript是一种简单易懂的语言.但最近编写大型模块化JavaScript应用程序的努力已经显示出其缺点.因此,谷歌(dart)和微软(TypeScript)都尝试为javascript提供一个类型系统,这可能有助于javascript中更好的模块系统也使它们能够用`JIT`进行优化.Mozilla试图限制javascript http://asmjs.org/spec/latest/#linking进行优化.如果你看到将来在javascript中会有某种继承:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Reserved_Words. (2认同)
  • 虽然我很欣赏你的答案的严谨性和热情,但我不认为必须能够理解为静态分析而设计的语言之美.也许解决这个问题的一种方法是将你与狗相关的文书工作(元数据)进行类比.假设文书工作提供了给狗狗进行治疗的清单.当然,这些信息对于您的狗来说不是必需的.但它让兽医在下次治疗你的狗时会有所作为. (2认同)
  • 也许是"protoclone"? (2认同)
  • 虽然我找到了您的答案(以及您几个月前就读过的同一主题的博客文章)提供了信息,但我看不到您如何“证明”原型继承比经典继承更好,或者为什么Object.create(foo)比新的Foo()更好。而且,IMO,没有理由证明两者都更好。他们只是不同。 (2认同)
  • 我同意@redline,"原型优于经典"的假设听起来是错误的,因为这是一个透视问题.例如,在工作中我遇到了许多情况,其中JavaScript放纵是团队工作的痛苦.我的意思是,如果我能够在一个由大师组成的团队中工作,我会同意这个提议:-) (2认同)
  • 你说"相比之下,经典继承要复杂得多",然后在Java中列出了一堆特性.这些只是模式,它们都可以用JavaScript实现.它们恰好已经在Java*开箱即用*中实现.IMO,Classical OOP是一种模式,可以使用JavaScript Prototypal对象扩展或串联实现,并通过API公开. (2认同)
  • 至于“通过闭包的私有变量”,我觉得这很不雅观。您正在创建一个带有成员变量的函数,该函数返回一个对象,该对象包含一个成员变量,而该成员变量又是一个引用外部范围内私有变量的函数。两个对象而不是一个。我觉得这很可怕而且令人费解。 (2认同)
  • 最后,"原型继承是动态的".这与原型继承本身无关,而是与用于表示对象的机制无关.在javascript中,对象表示为HashMaps,它们是动态的.您可以向HashMap添加额外的变量和函数(就像在我的语言Prototypal C中一样).但是(理论上)也可以使用静态的,固定大小的对象进行Prototypal继承,只要它们有一个名为"prototype"的指针即可.您还可以使用具有固定关系的语言,其中对象可以重新调整大小.Prototypal!=动态. (2认同)
  • @MichaelLafayette 哇。要消化的东西太多了。如果我没有解决你提出的所有观点,请原谅我。无论如何,我只是想告诉你,我不再赞同我的答案,因为我现在相信函数式编程比大多数 OOP 语言更好。我并不是说 OOP 不好。然而,在使用 OOP 语言超过 8 年之后,我意识到它们中的大多数与 Haskell 和 OCaml 等语言并不相同。事实上,我唯一不再喜欢的 OOP 语言是 [Fortress](https://en.wikipedia.org/wiki/Fortress_(programming_language)),但我仍然坚持使用 JavaScript。 (2认同)
  • @MichaelLafayette 您提供的“FactoryOfFactories”示例非常人为。事实上,我永远不会写那样的代码,所以你的整个论点都没有实际意义。我相信不言自明的代码和像这样的不透明代码既不是我会写的东西,也不是教其他人写的东西。 (2认同)
  • @AaditMShah-JavaScript要求您将实例化的数字加倍,以仅使变量私有,这一事实非常丑陋。您可能没有注意到它,因为您已经习惯了它,但是对于第一次看Javascript的人来说,它看起来很杂乱且不必要。 (2认同)

JUS*_*ION 39

请允许我实际回答内联问题.

原型继承具有以下优点:

  1. 它更适合动态语言,因为继承与它所处的环境一样动态.(这里对JavaScript的适用性应该很明显.)这允许你快速做事,比如在没有大量基础设施代码的情况下自定义类. .
  2. 与经典的类/对象二分法方案相比,实现原型对象方案更容易.
  3. 它消除了对象模型周围的复杂尖锐边缘的需要,如"元类"(我从未使用过类,我喜欢......对不起!)或"特征值"等.

但它有以下缺点:

  1. 检查原型语言的类型并非不可能,但这非常非常困难.大多数原型语言的"类型检查"是纯粹的运行时"鸭子打字"式检查.这不适合所有环境.
  2. 同样难以通过静态(或通常甚至动态!)分析来优化方法调度.它可以(我强调:可以)很容易效率很低.
  3. 类似地,对象创建在原型语言中可以(并且通常是)比在更传统的类/对象二分法中更慢.

我想你可以在上面的行之间进行阅读,并提出传统类/对象方案的相应优缺点.当然,每个区域都有更多,所以我将剩下的留给其他人回答.

  • 嘿,看,一个简洁的答案,不是粉丝。真的希望这是这个问题的最佳答案。 (2认同)

CMS*_*CMS 28

IMO原型继承的主要好处是它的简单性.

语言的原型性质可以迷惑谁是人经典的训练,但事实证明,其实这是一个真正简单而强大的概念,差分继承.

您不需要进行分类,代码更小,冗余更少,对象继承自其他更通用的对象.

如果你原型思考,你很快就会注意到你不需要上课......

原型继承在不久的将来会更受欢迎,ECMAScript第5版规范引入了该Object.create方法,它允许您以一种非常简单的方式生成一个从另一个继承的新对象实例:

var obj = Object.create(baseInstance);
Run Code Online (Sandbox Code Playgroud)

所有浏览器供应商都在实施该标准的新版本,我认为我们将开始看到更纯粹的原型继承......

  • "你的代码更小,冗余更少......",为什么?我已经查看了"差异继承"的维基百科链接,并且没有任何支持这些断言的内容.为什么经典继承会导致更大,更冗余的代码? (11认同)
  • 确切地说,我同意诺埃尔.原型继承只是完成工作的一种方式,但这并不能使其成为正确的方法.不同的工具将以不同的方式执行不同的工作.原型继承有其自己的位置.这是一个非常强大而简单的概念.话虽如此,缺乏对真正的封装和多态性的支持使JavaScript处于显着的劣势.这些方法比JavaScript具有更长的时间,并且它们在它们的主体中是合理的.因此,思考原型是"更好"只是错误的心态. (4认同)

Noe*_*ams 10

这两种方法之间的选择真的不多.要掌握的基本思想是,当JavaScript引擎被赋予要读取的对象的属性时,它首先检查实例,如果缺少该属性,它将检查原型链.这是一个显示原型和经典之间差异的例子:

原型

var single = { status: "Single" },
    princeWilliam = Object.create(single),
    cliffRichard = Object.create(single);

console.log(Object.keys(princeWilliam).length); // 0
console.log(Object.keys(cliffRichard).length); // 0

// Marriage event occurs
princeWilliam.status = "Married";

console.log(Object.keys(princeWilliam).length); // 1 (New instance property)
console.log(Object.keys(cliffRichard).length); // 0 (Still refers to prototype)
Run Code Online (Sandbox Code Playgroud)

使用实例方法的经典 (效率低,因为每个实例都存储它自己的属性)

function Single() {
    this.status = "Single";
}

var princeWilliam = new Single(),
    cliffRichard = new Single();

console.log(Object.keys(princeWilliam).length); // 1
console.log(Object.keys(cliffRichard).length); // 1
Run Code Online (Sandbox Code Playgroud)

高效的经典

function Single() {
}

Single.prototype.status = "Single";

var princeWilliam = new Single(),
    cliffRichard = new Single();

princeWilliam.status = "Married";

console.log(Object.keys(princeWilliam).length); // 1
console.log(Object.keys(cliffRichard).length); // 0
console.log(cliffRichard.status); // "Single"
Run Code Online (Sandbox Code Playgroud)

如您所见,由于可以操作以古典风格声明的"类"原型,因此使用原型继承确实没有任何好处.它是经典方法的一个子集.

  • 查看有关此主题的其他答案和资源,您的答案似乎是在说明:“原型继承是添加到 JavaScript 的语法糖的子集,以允许经典继承的出现”。OP 似乎在询问 JS 中的原型继承相对于其他语言中的经典继承的好处,而不是比较 JavaScript 中的实例化技术。 (2认同)