在JavaScript引擎方面,实现原型委托是否比基于类的继承有优势?

5

在使用现代JavaScript中的类时,我的理解是这只是对ECMAScript2015之前使用的相同基于原型的对象模型的一种语法糖。我喜欢直接使用原型链,但类肯定更容易。

因此,在JavaScript中,程序很可能都是根据基于类的语法来指定的,但执行时很可能是根据原型对象的规则执行的。因此,始终需要在JavaScript编写方式和执行方式之间进行某种转换。

无论通过浏览器和其他引擎如何实现JavaScript,我的问题是:

从编写JavaScript引擎的角度来看,以原型委托的方式实现面向对象语言是否具有性能或其他优势,而不是使用类?

====编辑

一个类似的问题(基于原型的语言中隐藏类的实现)有评论表明,传统意义上的类在编译器层面上更容易实现,因为它们可以被静态地布置到内存中(我认为这是暗示),但这不允许像JavaScript那样的动态结构。所以在我看来,原型委托可能是在编译器层面上实现动态对象的好选择?

从实现面向对象语言的角度来看,这不应该被标记为你正在创建实现的语言吗? - Teemu
1
原型继承模型的好处主要在于灵活性 - 它与鸭子类型方法非常契合。 - Bergi
“JavaScript的编写方式和执行方式之间存在某种转换” - 这种断开可能没有你想象的那么大。在幕后,所有内容都被转换为完全不同的数据结构。编译器可以在解析语法时更多或更少地进行内联转换。这实际上主要只是一种简写,没有更多的含义。 - deceze
1
我不确定你期望得到什么样的答案。对于像JavaScript这样灵活的语言,编写引擎要想达到类似于静态语言c或c++的性能是更加困难的,因为大部分优化都需要在运行时完成(如死代码删除、内联等)。但这样做的好处在于可以让使用该语言的用户受益。 - t.niese
2个回答

2
另一个角度是对象组合。
考虑以下内容:
class X { method() {} }
class Y extends X { method2() {} }

const y = new Y();

现在,在“经典”的面向对象编程中,y将是一个对象,并且它将有两个方法:methodmethod2
在原型(经典JavaScript)的意义上,y是一个对象。该对象本身没有任何东西,但在其原型上,它有一个method2。第一个method在哪里?好吧,如果你深入原型的构造函数,你会发现它也有一个原型,其中包含method
从Node REPL复制粘贴:
> class X { method() {} }
undefined
> class Y extends X { method2() {} }
undefined
> const y = new Y();
undefined
> y
Y {}
> y.prototype
undefined
> y.__proto__
Y {}
> y.__proto__.constructor
[Function: Y]
> y.__proto__.constructor.__proto__
[Function: X]

您需要能够支持那些对事物的原型进行猴子补丁(monkey-patch)的人:

> X.prototype.method = () => console.log('I am here now!');
[Function]
> y.method();
I am here now!

1
JavaScript在执行之前会以某种方式进行编译。这就是语言书写和执行之间的“转换”。此外,正如您所说,许多较新ES规范的功能实际上是语法糖。
无论您如何声明类,它们最终都将编译为类似的抽象语法树(如果我错了,请纠正)。可以通过中间编译器(如Babel)或直接执行实现来实现。
从这个角度来看,使用更抽象的类定义的主要缺点是,从编写JavaScript引擎的角度来看,它需要支持更广泛的语法。
可能的方法是将类语法简化为更本机的原型语法(中间编译)-这是我考虑实现它的方式。这会导致编译阶段的轻微性能损失。

“JavaScript在执行之前会被编译 - 这是该语言的一个重要特性。” - 嗯,JavaScript是解释型语言吗?我甚至记得有一种特定的实现方式,只有一个解析器和一个操作AST的解释器,以达到最小的内存占用。 - Bergi
个人认为JS属于灰色地带。我认为将JS代码经历的转换称为“编译”(具有词法作用域和提升)是公平的,但我也能理解这可能会引起混淆。它不像C语言那样是编译语言(可以争论C语言也可以被解释 - 任何人类可以理解的东西都可以),但也不像BASIC那样是真正的解释语言。我会进行编辑。 - Sami Hult
1
@Bergi FWIW,V8的后续版本(Chrome的JS引擎)会在脚本加载时立即将您的源代码转换为字节码。然后在JVM中解释此字节码,并在可能进行优化时将相关部分编译为本机代码(在上下文的生命周期内)。 但这与问题无关-我认为重点是JavaScript甚至没有传统的OOP /继承理解-它是基于原型的。语法或编译和优化方式并不重要。您仍然必须支持原型。 - Zlatko

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