如果我没有完全错,那么 JavaScript 中的每个框架/库/方法现在都倾向于模仿基于类的 OOP 样式继承。造成这种情况的原因似乎是人们认为基于类的 OOP 继承更容易理解,并且大多数程序员都知道 OOP。
以我的经验,我没有找到支持这两种观点的证据。我认为 javascript 原型继承很好(而且我怀疑将另一种范式强加于一种语言而不是它所基于的语言的有用性)。我遇到的大多数开发人员在经典 OOP 方面也不是那么好。那么选择经典 OOP 风格继承而不是原型继承的原因是什么?
如果我没有完全错,那么 JavaScript 中的每个框架/库/方法现在都倾向于模仿基于类的 OOP 样式继承。造成这种情况的原因似乎是人们认为基于类的 OOP 继承更容易理解,并且大多数程序员都知道 OOP。
以我的经验,我没有找到支持这两种观点的证据。我认为 javascript 原型继承很好(而且我怀疑将另一种范式强加于一种语言而不是它所基于的语言的有用性)。我遇到的大多数开发人员在经典 OOP 方面也不是那么好。那么选择经典 OOP 风格继承而不是原型继承的原因是什么?
请注意,即使您在争论基于原型的 OOP,您也将其称为“原型”,而基于类的 OOP 只是“OOP”。因此,您自己也受到这种偏见的困扰,认为 OOP=> 类、原型 => 其他东西。
而且由于大多数人认为无论遇到什么问题,OOP 都是正确的方法,那么原型肯定是次要的。
所以,要回答你的问题,有两个因素:
由于您仍然受第一个限制,因此您尝试解释原型是第二个的例外。纠正它们要容易得多:
有很多方法可以做对象,类只是静态语言最简单的一种。大多数人都被教导使用静态语言进行编程,并且他们中的大多数人都尝试使用任何一种语言,就像他们所学的第一种语言一样。
我认为答案就在您的问题中-大多数程序员对基于类的 OOP 比基于原型的 OOP 熟悉得多。
事实上,我什至会说大多数人不相信你可以拥有没有类的对象。
我觉得你好像已经知道你的问题的答案,因为你在说的时候说了一部分
造成这种情况的原因似乎是人们认为基于类的 OOP 继承更容易理解,并且大多数程序员都知道 OOP。
对于解决问题,两种范式都不比另一种更正确。我相信主要原因是现在每个人都通过 Java 学习 OOP。因此,当人们遇到 OOP 时,他们会认为“哦,类”,因为这是他们所熟悉的。每当他们想解决问题时,他们很可能会使用他们所知道的。
我还要声明,程序员使用他不熟悉的范式并没有什么好处。我们大多数人必须使用 javascript 进行客户端 Web 开发,并在服务器上使用基于类的 OOP 语言。每当我不得不查看应用程序的 javascript 端时,我个人不希望 OOP 阻抗不匹配。
在某种程度上,每个人都试图在 javascript 中实现基于类的 OOP 是一个教育问题。在另一个层面上,这是一个心理层面。
长期以来,我认为基于原型的 OOP 是基于类的 OOP 的弱、坏和错误的版本。然后,在大量信息泄露到我的脑海之后,我现在以更抽象的方式理解 OOP,并且发现两种方式都可以接受。
那么选择经典 OOP 风格继承而不是原型继承的原因是什么?实际上,我相信一些框架是“某种”组合方法。以寄生组合继承模式为例。这就是 YAHOO.lang.extend 正在做的事情。
它使用原型继承和辅助函数来继承原型和构造函数窃取。哇,这听起来很复杂......嗯是的 - 这是我的实现和测试,例如:
// Prototypal Inheritance
Object.prototype.inherit = function(p) {
NewObj = function(){};
NewObj.prototype = p;
return new NewObj();
};
// Paraphrasing of Nicholas Zakas's Prototype Inheritance helper
function inheritPrototype(subType, superType) {
var prototype = Object.inherit(superType.prototype);
prototype.constructor = subType;
subType.prototype = prototype;
};
function SubType(name, age) {
Parent.call(this, name);
this.age = age;
};
inheritPrototype(SubType, Parent);
SubType.prototype.getAge = function() {
return this.age;
};
我对此代码进行了测试:
describe 'Parisitic Combination Inheritance'
it 'should use inheritPrototype (to call parent constructor once) and still work as expected'
sub = new SubType("Nicholas Zakas", 29)
sub.toString().should.match /.*Nicholas Zakas/
sub.getAge().should.eql 29
charlie = new SubType("Charlie Brown", 69)
charlie.arr.should.eql([1,2,3])
charlie.arr.push(999)
charlie.arr.should.eql([1,2,3,999])
sub.arr.should.eql([1,2,3])
sub.should.be_an_instance_of SubType
charlie.should.be_an_instance_of SubType
(sub instanceof SubType).should.eql true
(sub instanceof Parent).should.eql true
end
end
当然,如果你注意我的文字,你会看到:Nicholas Zakas,我从那里得到这个的人;)这个的大胜利:instanceof 有效(有人说很重要,我有点同意);实例不共享引用类型(如数组)的状态(一个大问题!);父构造函数只调用一次(一个大问题!)。
顺便说一句,我在这里有大多数流行继承模式的示例:我的 TDD JS 示例
我认为该语言本身通过选择“新”作为关键字,并通过在语言规范中引入“构造函数”等概念来引导人们进入经典思维模式。在某种程度上,这是有限的——想象一下,如果我们有一个克隆关键字,思维方式的变化,以及特质 ala SELF 的概念。
当我编写我的第一个脚本时,拥有如此简单的语言既酷又方便。但是今天您不仅想切换按钮颜色,还想用 JavaScript 构建复杂的应用程序。其他人可能喜欢使用您流行的应用程序,并希望看到社区提供插件。
现在,使用 OOP 实现这一点要容易得多——尤其是因为很多程序员都熟悉 OOP 概念。
一个原因可能是您的服务器端很可能是 OO(ASP.NET、Java 等),因此在客户端上使用相同的范例更容易思考。不一定更好,但更容易。