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

JavaScript原型继承的缺点是什么?,javascript,inheritance,prototype-programming,Javascript,Inheritance,Prototype Programming,我最近看了,他对JavaScript原型继承赞不绝口,似乎这是自切片白面包以来最好的东西。考虑到Crockford的声誉,很可能是这样 有人能告诉我JavaScript原型继承的缺点是什么吗?(例如,与C#或Java中的类继承相比)在我的经验中,一个显著的缺点是不能通过在闭包中封装变量来模拟Java的“私有”成员变量,但仍然可以让随后添加到原型中的方法访问它 i、 e: 这让那些被教导将成员变量私有化的OO程序员们感到困惑。我认为主要的危险在于多方可能会重写对方的原型方法,从而导致意外行为 这尤

我最近看了,他对JavaScript原型继承赞不绝口,似乎这是自切片白面包以来最好的东西。考虑到Crockford的声誉,很可能是这样


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

在我的经验中,一个显著的缺点是不能通过在闭包中封装变量来模拟Java的“私有”成员变量,但仍然可以让随后添加到原型中的方法访问它

i、 e:


这让那些被教导将成员变量私有化的OO程序员们感到困惑。

我认为主要的危险在于多方可能会重写对方的原型方法,从而导致意外行为

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

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

String.prototype.trim = function() {
    // remove all ' ' characters from left & right
}
然后,另一方可能会创建一个新的定义,使用一个完全不同的签名,使用一个指定要修剪的字符的参数。突然,所有不传递任何信息到
trim
的代码都无效

或者另一方重新实现剥离
''
字符和其他形式的空白(例如制表符、换行符)的方法。这可能会在一段时间内被忽视,但会导致今后的奇怪行为

根据项目的不同,这些可能被视为远程危险。但它们是可能发生的,根据我的理解,这就是为什么像这样的库选择将所有方法保留在名称空间中,而不是添加原型方法


更新:显然,这是一个判断调用。其他库——也就是恰当命名的库——确实遵循原型路线。我并不是想说一种方法是对的还是错的,只是我听到过一种观点,反对过多地使用原型方法。)

在Javascript中对现有对象进行子分类与从C++中的类继承时,我遗漏了一些东西:

  • 无论是哪位开发人员编写的,都没有一种标准(内置于语言中)的编写方式看起来是相同的
  • <> LI>编写代码不自然产生接口定义,类头文件在C++中的方式。
  • 没有标准的方法来处理受保护和私有的成员变量或方法。有些事情有一些约定,但不同的开发人员的做法也不同
  • 当您在定义中犯了愚蠢的键入错误时,没有编译器步骤可以告诉您
  • 当你想要的时候,没有类型安全
  • 不要误会我的意思,JavaScript原型继承与VC++的方式有很多优点,但这些是我发现JavaScript工作不太顺利的地方。 4和5与原型继承没有严格的关系,但是当您有一个具有许多模块、许多类和大量文件的大型项目,并且您希望重构一些类时,它们就会发挥作用。在C++中,可以更改类,更改尽可能多的调用方,然后让编译器找到需要修复的所有剩余引用。如果您添加了参数、更改了类型、更改了方法名称、移动了方法等。。。编译器将显示您是否需要修复问题

    在Javascript中,要发现所有可能需要更改的代码片段,必须严格执行所有可能的代码路径,以查看是否遗漏了某些内容或输入了某些错误,这是不容易的。虽然这是javascript的一个普遍缺点,但我发现在一个大型项目中重构现有类时,它尤其起作用。我已经接近一个重要的JS项目的发布周期结束,决定不做任何重构来修复问题(尽管这是更好的解决方案),因为在JS中没有找到比C++更高的可能的风险。
    因此,我发现在JS项目中进行某些类型的OO相关更改的风险更大。

    我想知道我的直觉答案是否与专家的想法相符

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

    通过JavaScript“duck typing”,有人可以继承我的一个对象,并以几乎任何可以想象的方式更改其成员函数和值(是的,我知道函数在JavaScript中是值),这样,他们传递给我的函数的对象与我期望传递给我的函数的对象没有任何相似之处


    我觉得没有什么好方法可以让人清楚地知道函数应该如何调用。

    我怀念能够将接口与实现分离开来的感觉。在具有继承系统的语言中,继承系统包括
    抽象
    接口
    等概念,例如,您可以在域层声明接口,但将实现放在基础结构层。(参见…)JavaScript的继承系统没有办法做到这一点。

    不要包括它会让多年来一直使用类继承编程的开发人员感到头痛。这一点很明显:-)听起来你是说JavaScript缺少类似于
    protected
    关键字的功能。@Rice不,不仅仅是-pr中的函数
    String.prototype.trim = function() {
        // remove all ' ' characters from left & right
    }