【问题标题】:javascript inheritance. How to extend a classjavascript继承。如何扩展一个类
【发布时间】:2013-08-12 04:06:31
【问题描述】:

我正在做一个国际象棋游戏。我想做一个抽象的片断类,然后可以通过pawn/knight/rook/etc进行扩展。假设我的作品类如下所示:

"use strict";
function Piece(color) {
    this.color = color;
    this.type = "Abstract";
}
Piece.prototype.sayName = function sayName(){
    alert(this.type);
}
Piece.prototype.movePiece(oldPosition, newPosition){
};

我会这样实例化它:

var abstractPiece = new Piece("Black");

现在假设我想创建一个 Pawn 类,我想实例化如下。

var pawnOne = new Pawn("Black");

我希望 Pawn 具有相同的 sayName 函数,但我希望它具有不同的 movePiece 函数,因为 Pawn 有自己独特的移动方式。我将如何制作 Pawn,使其扩展 Piece,并覆盖 Piece 的 movePiece 函数?

【问题讨论】:

  • 你能写出这样 Piece 永远不需要移动功能吗?我认为所有的棋子都有非常独特的允许移动,所以没有理由定义移动然后也超载它。
  • 可能。实际上我已经让每一个部分都工作了,但是有很多共享代码,因为我不知道如何扩展抽象类。即使这是可能的,我问也是因为我想知道如何做到这一点。
  • 另外,您应该考虑阅读相关内容,也许点击 javascript 标签并转到标签 wiki 并阅读其中的一些内容。

标签: javascript oop inheritance extends


【解决方案1】:

我会稍微不同地定义一个片段以使其更具可扩展性。

var Piece = function(color) {
    return {
        color : color,
        type : "Abstract",
        sayName : function sayName(){
            alert(this.type);
        },
        movePiece : function(oldPosition, newPosition){
        }
    };
}

var Pawn = function(color) {
    var pawn = Piece("Black");
    pawn.movePiece = function(oldPosition, newPosition) { 
        // pawn move here 
    };
    return pawn;
}

然后您可以通过执行Piece("Black")Pawn("Black") 来创建棋子或棋子。

【讨论】:

  • 你能解释一下为什么它更具可扩展性吗?
  • 这似乎是一个不错的策略。如果我要向 pawn 添加一个名为 movePiece 的函数,它会覆盖 Piece 中的 movePiece 函数吗?假设,由于没有实际实例化并需要移动的 Piece,我可以将它从 Piece 中取出,但假设我想覆盖该函数,我可以吗?
  • 可扩展可能不是最好的词。我喜欢这种风格的原因是因为它将类定义限制在一个位置,而不是在任何地方放置prototype 调用,并且它避免使用new。另外,我不知道原型函数如何与专门设置的属性发生冲突,因此可以避免这种情况(尽管我必须记得查一下)。
  • 因为Piece()返回一个对象,你可以覆盖movePiece属性,一切都会按预期工作。
【解决方案2】:

这是另一个解决方案,

作为另一种通用解决方案,我将一个函数附加到默认的 javascript 超级函数。然后它将应用于所有 javascript 实例。

Function.prototype.extend=function(superClass){
    for (var property in superClass.prototype){
        if(property!='extend' && property!='type' && !this.prototype[property]){
            this.prototype[property] = superClass.prototype[property];
        }
    }
}

在加载任何 javascript 之前,应首先应用上述代码。

那你就可以这样使用了。

//Super class constructor
function Collection(){
    this.type = 'Collection';   
}

//sub class
function HashSet(){
    this.type='HashSet';
    HashSet.extend(Collection);
}

【讨论】:

    【解决方案3】:

    为了补充 Matt 的答案,我还将通过简单地提供不同的名称来让每种特定类型调用 movePiece 的“基本”逻辑,如下所示:

    var Pawn = function(color) {
        var pawn = Piece("Black");
        pawn.movePawn = function(oldPosition, newPosition) { 
            // special pawn-specific logic for moving here
            // now call 'base' logic to actually move piece to the new position
            pawn.prototype.movePiece(oldPosition, newPosition);
        };
        return pawn;
    }
    

    这将允许所有棋子共享相同的逻辑以实际移动到板上的新位置,但也允许根据棋子的类型自定义逻辑。

    【讨论】:

      【解决方案4】:

      当您在 Coffeescript 中扩展类时,编译器生成的代码将一个 JS 类“扩展”到另一个。我得到了这个:

      var Animal, Dog, _ref,
        __hasProp = {}.hasOwnProperty,
        __extends = function(child, parent) {
           // This function takes a child class and extends it with all
           // attributes that are included in the parent class.
           for (var key in parent) {
               // Need to check that this property was actually a key of the parent.
               // The Coffeescript compiler was defensive here against changes to
               // the hasOwnProperty function, but you can probably get by with
               // parent.hasOwnProperty(key).
               if (__hasProp.call(parent, key))
                   child[key] = parent[key];
           }
           function ctor() {
               this.constructor = child;
           }
           // Set the default constructor of the child based on the parents.
           ctor.prototype = parent.prototype;
           child.prototype = new ctor();
           // Make it possible to call the __super__ easily.
           child.__super__ = parent.prototype;
           return child;
       };
      
      Animal = (function() {
        function Animal() {}
      
        // To add methods to this class, you would do this:
        //   Animal.prototype.foo = function() {...}
      
        return Animal;
      
      })();
      
      Dog = (function(_super) {
        __extends(Dog, _super);
      
        function Dog() {
          _ref = Dog.__super__.constructor.apply(this, arguments);
          // This is where you would extend the constructor to add
          // functionality to the subclass.
          return _ref;
        }
      
        // To add methods to this subclass, or to override base class
        // methods, you would do this:
        //   Dog.prototype.bar = function() {...}
      
        return Dog;
      
      })(Animal);
      

      通过输入

      class Animal
      
      class Dog extends Animal
      

      http://coffeescript.org/ 处进入编译器,然后对结果进行注释。

      【讨论】:

      • 编译器的输出不是解释某事的好方法。
      • 我已经在 CoffeeScript 和 TypeScript 中看到了这一点。像这样扩展它似乎太复杂了,不值得。我认为这部分是因为它是编译代码而不是手写。我想我相信有更好的方法。我已经准备好犯错了。
      • @MattBryant 你是绝对正确的。我已经浏览了该代码并对其进行了评论。许多编译后的输出(例如:_ref 和 __hasOwn)只是防御性的,如果您手动执行此操作,可能会被丢弃。
      猜你喜欢
      • 2011-10-19
      • 2016-02-28
      • 1970-01-01
      • 2019-05-04
      • 1970-01-01
      • 1970-01-01
      • 2012-04-21
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多