繁体   English   中英

为什么Javascript默认不支持继承?

[英]Why Javascript does not support inheritance by default?

从OOPS基础开始,我总是使用继承作为代码重用的强大工具,

例如,如果我在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不支持经典继承作为默认选项?

[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();

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

此外,Javascript从来没有真正“意味着”我们今天用它做的所有事情(从Node.js到ASM.js)。 它仍然相关的事实是Brendan Eich和Co.的遗嘱。所以你可能想知道为什么X或Y从未在JS中实现,但事实是我们使用JS来解决20年前无法预见的问题。

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

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

那些作者倾向于给予他们的祝福而不是“接口继承” - 但是在诸如JavaScript之类的鸭子类型语言中,没有必要明确地声明这样的继承。

在JS中,您可以通过简单地将其作为多个对象的属性来“重用”相同的函数。 无论你需要什么样的遗产,你都可以从无到有。

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);

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

据我所知,将TestB的原型设置为新的TestA允许“instanceof”运算符的逻辑包含。

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

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

此外,JavaScript不支持传统的面向对象风格的主要原因是它的创始理念。 创始哲学是自由。 这种自由旨在允许开发人员设计自己的样式以满足项目的需求。

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM