10

从 OOPS base 开始,我一直使用继承作为代码重用的强大工具,

例如,如果我在 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.
};

我可以用has-ajavascript 中的关系来做到这一点,但我看到的缺点是,我也必须重新定义派生类中的每个函数。

示例:在每个 rook、knight、pawn、king.... 等中再次重新定义 getTeamColor()。

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

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

我的问题是,为什么 javascript 不支持将经典继承作为默认选项?

4

5 回答 5

17

[2018 年更新] JavaScript 现在显然支持与原生语言特性的继承。

class A { }
class B extends A { }

[/更新]

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();
于 2013-04-28T08:40:40.230 回答
7

因为 Javascript 不是一种基于类的面向对象语言,而是一种原型语言。这只是一个设计决定。

此外,对于我们今天用它做的所有事情(从 Node.js 到 ASM.js)来说,Javascript 从来都不是真正的“意思”。它仍然相关的事实是 Brendan Eich 和 Co. 的证明。所以你可能想知道为什么 X 或 Y 从未在 JS 中实现,但事实是我们将 JS 用于 20 年前无法预见的事情。

于 2013-04-28T08:33:05.367 回答
1

许多关于各种传统 OO 语言(包括 Java、C# 和 C++)的好书都特别建议不要在可能的情况下使用“实现继承”。示例:Joshua Bloch 的《Effective Java》。

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

这些作者倾向于支持“接口继承”——但在 JavaScript 这样的鸭式语言中,不需要显式声明这种继承。

在 JS 中,您可以通过简单地将其分配为多个对象的属性来“重用”相同的功能。无论您需要何种继承方式,您都可以凭空变出它。

于 2013-04-28T08:39:13.403 回答
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);
于 2013-04-28T08:39:45.997 回答
0

以下代码块将从另一个 JavaScript 原型“扩展”,并确保“instanceof”运算符对基类和派生类正确工作。

据我所知,将 TestB 的原型设置为新的 TestA 允许“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
于 2017-12-25T19:20:12.430 回答