【问题标题】:Does using prototypes in JavaScript have any real world advantages?在 JavaScript 中使用原型是否有任何现实世界的优势?
【发布时间】:2010-08-29 00:11:06
【问题描述】:

我刚刚完成了 Doug Crockford 的 The Good Parts,他提供了三种不同的继承方式:emulation 的经典模型、基于原型的继承和函数继承。

在后者中,他创建了一个函数,一个类似工厂的函数,它输出的对象增加了所需的方法,这些方法建立在其他对象的基础上;类似于:

var dog = function(params) {
    // animal is the 'super class' created
    // the same way as the dog, and defines some
    // common methods
    var that = animal(params);
    that.sound = 'bark';
    that.name = function () {};
    return that;
}

由于以这种方式创建的所有对象都将引用相同的函数,因此内存占用量将比使用 new 运算符时低得多。问题是,原型方法在这种情况下会提供任何优势吗?换句话说,对象原型是否以某种方式“更接近金属”以提供性能优势,或者它们只是一种便利机制?

编辑:我会简化问题。原型与通过对象组合进行的模拟。只要您不要求所有对象实例都使用新方法进行更新,而这只是原型提供的便利,那么首先使用原型有什么好处吗?

我给 Doug Crockford 发了电子邮件,他是这样说的:

[使用上面的函数方法与原型] 并没有那么多内存。如果你有大量的对象乘以大量的方法,那么你可能想要原型化。但是现在记忆很丰富,只有极端的应用程序才会注意到它。

原型可以使用更少的内存,但检索速度可能会稍慢,尤其是在链很长的情况下。但一般来说,这并不明显。

【问题讨论】:

    标签: javascript inheritance function prototype


    【解决方案1】:

    实例都引用相同的函数等。每次调用“dog”都会创建一个新的“name”函数实例。

    【讨论】:

    • 嗯。你说得对,我怎么没看到。那不是很可怕吗? :)
    • 问题是:与简单地从多个对象中引用相同的函数相比,原型是否提供任何优势?
    • 不用为每个实例设置单独的实用函数副本,您可以节省大量内存。
    • @mitjak:我不知道是否有任何 JS 实现可以做到,但有些语言可以,在这种情况下,只是(透明地)创建所创建函数的 one 静态实例在dog 中,每次调用dog 时,它都会为该函数提供一个新的引用。如果每个函数都必须具有不同的标识,则可能每次都会生成此函数,但可能会产生很小的开销,但每个生成的函数都将引用相同的字节码(可能还有不同的闭包)。无论如何,开销可能微不足道。
    • @Pointy 我的代码是一个不好的例子。假设引用被正确维护,以便每个实例引用相同的“核心”对象。那怎么办?我感兴趣的是原型是否提供任何性能优势,因为它们的行为可以在一定程度上被模仿。
    【解决方案2】:

    对此有很多意见,Crockford 不一定是正确的。

    修改原型的主要缺点是它可能会使与其他 javascript 库的工作变得更加困难。

    但是 Crockford 的函数式创建类的方法的缺点是,您不能轻松地将方法或字段添加到类型的所有实例。

    关于 Crockford 关于 javascript 中的类和继承的观点,请参阅 Closure: The Definitive Guide,了解一些关键的 cmets: http://my.safaribooksonline.com/9781449381882/I_sect1_d1e29990#X2ludGVybmFsX0ZsYXNoUmVhZGVyP3htbGlkPTk3ODE0NDkzODE4ODIvNTE0

    像 Dojo、Google Closure Library(这似乎是复制 Dojo 的风格)之类的库,也许 YUI 有自己的类系统,这似乎是一个很好的中间地带。我最喜欢 Dojo 的系统可能是最好的,因为它支持 Mixins,不像 Closure。其他一些与 gui 工具包无关的类系统包括 Joose、JS.Class 和 JavascriptMVC(如果使用 jquery,请查看最后一个)。

    【讨论】:

    • 感谢您的建议,但有一个关于此的问题:“修改原型的主要缺点是它可能会使与其他 javascript 库的工作变得更加困难。”为什么我要修改内置对象的原型?我主要谈论的是我自己创建的对象的原型。
    • @mitjak 修改内置的原型有点流行;例如,请参阅 Prototype 库,它以狂野的方式完成它。
    • 它很受欢迎,但这并不是我想要在这里找到的。
    【解决方案3】:

    我曾经创建了一个 GUI,它由一个类支持,该类对它所需的信息没有很好的基于事件的支持。 GUI 实现了一个通用接口,其中传入了该类的 instance,因此我无法从该类继承,所以我做了类似于基于原型的继承的事情,我创建了一个代理对象,它包装了当它传递给我的 GUI 时该类的实例。代理拦截改变状态的感兴趣的方法,并将它们报告为事件。然后整个 GUI 围绕使用这些事件展开。

    在这种情况下,创建一个单独的类来包装传入的实例并重现相同的接口会很烦人。由于创建了所有冗余函数,这实际上会导致更多开销(并不重要)。

    根本没有其他可行的选择。唯一的选择是:

    1. 创建一个对象,该对象构成传递给 GUI 的对象(就像我上面提到的那样)。然后,该对象将复制原始类中的每个函数以实现相同的接口,并添加事件,因此它实际上与代理对象方式相同。
    2. 在其传入的对象中具有 GUI 跟踪状态突变。这将是痛苦并且容易出错。

    【讨论】:

      猜你喜欢
      • 2020-11-07
      • 2011-01-15
      • 2013-09-22
      • 2011-05-31
      • 2023-03-26
      • 1970-01-01
      • 2017-03-04
      • 1970-01-01
      相关资源
      最近更新 更多