2013-04-28 67 views
6

如从OOPS基,我总是使用继承作为代码重用的有力工具,为什么Javascript默认不支持继承?

实施例,如果我写在OOPS棋程序,当我实施is-a关系为,

Class Piece{ 
    int teamColor; 
    bool isLive; 
    Positon pos; 
    int Points; 
    ....... 
    int getTeamColor(){....} 
    ....... 
}; 

Class Rook extend Piece{ //`is-a` 
...... // No getTeamColor() definition here.. because the parent has the definition. 
}; 

Class Pawn extend Piece{ //`is-a` 
......// No getTeamColor() definition here.. because the parent has the definition. 
}; 

我可以在JavaScript中使用has-a关系,但我看到的缺点是, 我必须重新定义派生类中的每个函数。

例:getTeamColor的重新定义(在每一个车,马,卒,王再)......等。

 var Pawn = function(teamColor,pos){ 
    var piece = new Piece(teamColor,pos); 
    ....... 

    this.getTeamColor = function(){   
      return piece.getTeamColor(); 
    }; 
    } 

我的问题是,为什么 多年平均值的JavaScript支持经典的继承作为默认选项?

+0

看看jOOPL(http://joopl.codeplex.com)。它是一个100%JavaScript面向对象的库,它增强了支持基于类的OOP的语言。因此,它具有继承性和多态性(以及更多的功能)。我即将在几天内发布新版本并进行更多改进。 – 2013-04-28 08:36:02

+6

JavaScript支持继承*,如果你使用它*。查找“JavaScript原型链”。至于“为什么JavaScript不支持经典继承作为默认选项?” - 因为这就是JavaScript的定义。为什么Java没有Traits但是Scala呢?为什么Python支持MI,尽管Ruby不支持?为什么C++没有Dylan的Multiple Dispatch呢?为什么埃菲尔允许LSP的断开?那么,他们是*不同的语言*并声称一个是适当的 - 通过间接手段的“经典” - 是否认另一种方法是(或更多)是有效的。 – user2246674 2013-04-28 08:37:25

+0

来自Mozilla开发者网络的关于javascript对象模型细节的全文。 [链接到这里](https://developer.mozilla.org/en-US/docs/JavaScript/Guide/Details_of_the_Object_Model)。本文介绍继承,层次和关系,同时在Java(基于类)和Javascript(基于原型)之间进行比较。 – 2013-04-28 09:08:49

回答

13

JavaScript确实支持以原型方式继承。你需要的不是类,而是行为的封装和覆盖的能力。

function Piece() { } 

Piece.prototype.color = "white"; 
Piece.prototype.getColor = function() { return this.color } 
Piece.prototype.move = function() { throw "pure function" }; 

function Pawn() { } 
Pawn.prototype = new Piece();  
Pawn.prototype.move = function() { alert("moved"); } 

现在:

var p = new Pawn(); p.color = "black"; 

> p instanceof Piece 

真正

p instanceof Pawn 

真正

p.getColor() 

“黑”

p.move() 

警报...

这是基本的做法,有许多图书馆,在那里,把它变成的东西,熟悉了希望班的家伙 - 这么说。

例如与JayData可以写以前在多个封装方式(自动构造函数调用的奖金链:

var Piece = $data.Base.extend("Piece", { 
    move: function() { throw "pure class" } 
}); 

var Pawn = Piece.extend("Pawn", { 
    move: function() { ... } 
}); 

var p = new Pawn(); 
7

因为Javascript不是class-based object-oriented language,而是一个prototypal之一。这只是一个设计决定。另外,对于我们今天所做的所有事情(从Node.js到ASM.js),Javascript从来都不是“真正意义上的”。它仍然相关的事实是Brendan Eich和Co.的遗嘱。所以你可能想知道为什么X或Y从未在JS中实现过,但事实是,我们使用JS来处理20年前不可预见的事情。

1

许多关于各种传统面向对象语言(包括Java,C#和C++)的好书特别建议不要在可能的情况下使用“实现继承”。示例:Joshua Bloch的有效Java。

奇怪的事实是,虽然实现继承似乎给您的代码定期“形状”,但它并不真正帮助您解决问题;更常见的是,它从长远来看会导致问题。

这些作者倾向于将他们的祝福改为“接口继承” - 但是在鸭子类型的语言如JavaScript中,不需要显式声明这种继承。

而在JS中,您可以通过简单地将它指定为多个对象上的属性来“重用”相同的功能。无论你需要什么样的继承风格,你都可以从无到有。

1

JavaScript甚至没有真正的OOP风格的类,你只是能够模拟类似的东西。

在你的榜样,你可以通过做

var Pawn = function(teamColor, pos) { 
    Piece.call(this, teamColor, pos); 
} 

但是,你通常应该重视方法的功能原型,而不是任何新创建的对象实现继承。在这种情况下,您可以通过设置原型链来模拟继承,例如,像CoffeeScript那样:

var a, b, _ref, 
    __hasProp = {}.hasOwnProperty, 
    __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }; 

a = (function() { 
    function a() {} 

    return a; 

})(); 

b = (function(_super) { 
    __extends(b, _super); 

    function b() { 
    _ref = b.__super__.constructor.apply(this, arguments); 
    return _ref; 
    } 

    return b; 

})(a); 
+4

对于所需的任务,这是imho矫枉过正(并且有点乱码):重写类树下的行为。 – 2013-04-28 08:48:43

0

下面的代码块将从“扩展”一个JavaScript的原型其他,并确保“的instanceof”操作符可以正常工作为基础,并派生类。

从我可以告诉,TESTB的原型设置为一个新的种皮允许“的instanceof”操作符的逻辑相合。

将此传递给TestA为新实例提供了所有所需的属性和方法。

这样做是文体欲望和实用欲望之间的一种平衡。如果你不得不支持它,这将适用于大多数浏览器,甚至Internet Explorer。它也有帮助,因为使同一块中包含的方法“感觉”很像您的传统OO语法。

此外,JavaScript不支持传统风格的OO的主要原因是因为其创立理念。创立哲学是自由。这种自由旨在让开发人员设计自己的风格以适应项目的需求。

function TestA(){ 
    var me = this; 

    me.method = function(){ 
    } 
} 

function TestB(){ 
    TestA.call(this); 
    var me = this; 

    me.otherMethod = function(){ 
    } 
} 
TestB.prototype = new TestA(); 

var test = new TestB(); 

console.log(test); 

console.log(test instanceof TestB); 
console.log(test instanceof TestA); 

//TestA { method: [Function], otherMethod: [Function] } 
//true 
//true