JavaScript原型继承的缺点是什么?

时间:2011-07-05 15:51:56

标签: javascript inheritance prototype-programming

我最近看了Douglas Crockford's JavaScript presentations,他对JavaScript原型继承表示赞同,好像这是切片白面包以来最好的东西。考虑到克罗克福德的声誉,很可能是。

有人可以告诉我JavaScript原型继承的缺点是什么? (例如,与C#或Java中的类继承相比)

5 个答案:

答案 0 :(得分:8)

根据我的经验,一个显着的缺点是你不能通过在变量包中封装变量来模仿Java的“私有”成员变量,但仍然可以使用随后添加到原型中的方法。

即:

function MyObject() {
    var foo = 1;
    this.bar = 2;
}

MyObject.prototype.getFoo = function() {
    // can't access "foo" here!
}

MyObject.prototype.getBar = function() {
    return this.bar; // OK!
}

这会让OO程序员感到困惑,他们被教导要将成员变量设为私有。

答案 1 :(得分:5)

在Javascript中对现有对象进行子类化而不是从C ++中的类继承时我想念的事情:

  1. 无论哪个开发人员编写它,都没有标准的(内置于语言)编写方式。
  2. 编写代码自然不会像C ++中类头文件那样生成接口定义。
  3. 没有标准的方法来执行受保护的和私有的成员变量或方法。某些事情有一些约定,但不同的开发人员也会采用不同的方式。
  4. 当您在定义中犯了愚蠢的输入错误时,没有编译步骤告诉您。
  5. 如果你想要它,就没有类型安全。
  6. 不要误解我的意思,javascript原型继承的方式与C ++相比有很多优势,但这些是我发现javascript工作不太顺畅的地方。

    4和5与原型继承没有严格的关系,但是当你有一个包含很多模块,很多类和大量文件的大型项目并且你希望重构某些类时,它们会发挥作用。在C ++中,您可以更改类,更改尽可能多的调用者,然后让编译器找到需要修复的所有剩余引用。如果您已添加参数,更改的类型,更改的方法名称,移动的方法等...编译器将显示您需要解决的问题。

    在Javascript中,没有简单的方法来发现需要更改的所有可能的代码片段,而无需逐字地执行每个可能的代码路径,看看你是否错过了什么或者做了一些错字。虽然这是javascript的一般缺点,但我发现它在重构大型项目中的现有类时特别有用。我已经接近一个大型JS项目的发布周期结束,并决定我不应该做任何重构来解决问题(即使这是更好的解决方案),因为没有找到所有可能的后果的风险JS中的变化远远高于C ++。

    因此,我发现在JS项目中进行某些类型的与OO相关的更改风险更大。

答案 2 :(得分:2)

我认为主要的危险是多方可以覆盖彼此的原型方法,导致意外行为。

这是非常危险的因为这么多程序员对原型“继承”(我称之为扩展名)感到兴奋,因此开始在所有地方使用它,添加左右方法可能具有模糊或主观行为。最终,如果不加以控制,这种“原型方法扩散”可能会导致代码难以维护。

一个流行的例子是trim方法。它可能由一方实施:

String.prototype.trim = function() {
    // remove all ' ' characters from left & right
}

然后另一方可以使用完全不同的签名创建 new 定义,并使用一个参数指定要修剪的字符。突然间,所有未传递给trim的代码都没有效果。

或者另一方重新实施该方法以剥离' '个字符其他形式的空白区域(例如,标签,换行符)。这可能会被忽视一段时间,但会引发奇怪的行为。

根据项目的不同,这些可能被视为远程危险。但它们可能会发生,而且根据我的理解,这就是Underscore.js等库选择将所有方法保留在命名空间而不是添加原型方法的原因。

更新:显然,这是一个判断调用。其他库 - 即恰当命名的Prototype - 做< / em>走原型路线。我不是说一种方式是对还是错,只是这是我听到的反对使用原型方法过于宽泛的论点。)

答案 3 :(得分:1)

我错过了能够将界面与实现分开。在具有包含abstractinterface等概念的继承系统的语言中,您可以使用在您的域层中声明您的界面,但将实现放在您的基础架构层中。 (参见onion architecture。)JavaScript的继承系统无法做到这一点。

答案 4 :(得分:0)

我想知道我的直觉答案是否符合专家的想法。

我担心的是,如果我在C#中有一个函数(为了讨论起见)需要一个参数,任何编写调用我函数的代码的开发人员都会立即从函数签名中知道它需要什么类型的参数以及什么它返回的值的类型。

使用JavaScript“duck-typing”,有人可以继承我的一个对象,并以几乎任何可想象的方式更改其成员函数和值(是的,我知道函数是JavaScript中的值),以便它们传入的对象我的函数与我期望传递函数的对象没有任何相似之处。

我觉得没有什么好方法可以明确表示如何调用函数。