【问题标题】:A class within a class?班级中的班级?
【发布时间】:2019-04-26 03:34:57
【问题描述】:

理想情况下,我想做如下的事情:

class Chess = {
  constructor() {
    this.board = ...;
    ...
  };

  class Square = {
    constructor(row, col) {
      this.row = row;
      this.col = col;
  };
};

我的主要动机是分开定义 Chess 和 Square 类,例如:(这里指的是 Chess 类)

this.empty(square)

可以缩短为

square.empty()

更易读,更简洁。

不幸的是,我不能只做一个

Square.empty()

方法,因为结果取决于国际象棋类中的信息和

square.empty(chess)

没有真正的改进。

我有一个 Square 类的原因是这样的

square.up()

似乎比类似的东西好得多

[row, col + 1]

您对我将如何完成上述任务有什么建议吗?以某种方式在类中编写类或完全是其他方式?

编辑:

按照 likle 和 alex 的建议,我做了以下事情:

我在类 Square 中添加了一个上下文属性

class Square = {
  constructor(context, row, col) {
    this.context = context;
    this.row = row;
    this.col = col;
  };
};

然后将 Chess.prototype 中的一些方法重新定义为 Square.protoype。例如:

// before
Chess.prototype.empty = function (square) {
  return this.piece(square) === 0;
};

// after
Square.prototype.empty = function () {
  return this.piece() === 0;
};

这意味着每次创建 Square 对象时,我都需要添加上下文。例如:

new Square(3, 4); // before
new Square(this, 3, 4); // after
new Square(this.context, 3, 4); // sometimes like this

为了使代码更具可读性,我创建了以下方法:

Chess.prototype.createSquare = function (row, col) {
  return new Square(this, row, col);
};

所以有时可以创建一个 Square 对象

this.createSquare(3, 4);

【问题讨论】:

  • 您可以将定义分开,只让Chess 实例化Square 的实例。

标签: javascript class oop nested


【解决方案1】:

目前有are no nested classes。您可以做的是拥有两个单独的类,ChessChessSquare - 并引用 ChessSquare 的构造函数中传递的国际象棋并将其保存为属性。这样您就不必在 ChessSquare 的方法中传递它:

  class ChessSquare = {
    constructor(chess, row, col) {
      this.chess = chess;
      this.row = row;
      this.col = col;
    }

    empty() {
      // "this.chess" references the chess, and "this" references the square.
    }
  };

您可能希望在 Chess 类本身中创建 ChessSquare 的所有实例。

【讨论】:

    【解决方案2】:

    有人可能会争辩说 JavaScript 没有这样的“嵌套”类——例如,一个类无法使用父类范围,除了父类属性之外,它对任何东西都没有意义(static声明),但 JavaScript 中的类与任何其他类一样只是一个对象,因此您不妨定义一个并使用另一个类的属性来引用它:

    class Chess {
    }
    
    Chess.Square = class {
    };
    

    (是的,类名是可选的)

    然后您可以执行以下操作:

    new Chess.Square();
    

    通常你对一个类或一个类的对象所做的一切。

    JavaScript可以让你做的是嵌套构造函数。即使使用上述符号,JavaScript 类本质上也是它的构造函数——Chess.prototype.constructor === Chess。换句话说,类在运行时“衰减”为构造函数。嗯,有一些额外的元数据通过 ECMAScript 和 一些 差异与它们相关联,但以下是嵌套构造函数以访问外部范围的示例:

    function Chess() {
        const chess = this;
        function Square() { /// Obviously, this function/constructor/class is only available to expressions and statements in the Chess function/constructor/class (and if explicitly "shared" with other code).
            Chess; /// Refers to the outer constructor/class -- you can do `new Chess()` etc
            this; /// Refers to this Square object being created
            chess; /// Refers to what `chess` declared outside this method, refers to at the time of creating this Square object
        }
    }
    

    上面使用了所谓的“闭包”,您还需要了解 JavaScript 中作用域的工作原理。在 Java 中,上面指定的 Chess 类称为嵌套 instance 类,而不是嵌套 static 类。第一个使用 class 关键字的示例确实指定了后者的一种形式(静态类)。

    JavaScript 的特点是它实际上比传统 OOP 模型所描述的更灵活,并且“嵌套类”对于不同的人以及在不同的程序中可能意味着不同的东西。但是该语言显然允许您做很多事情,这些事情可能会帮助您实现您的预​​期模型或使您的代码难以阅读(尤其是对于那些不像您了解那么多 JavaScript 的人)和调试。这是在使用嵌套类之前需要解决的权衡问题。

    【讨论】:

      【解决方案3】:

      以下代码运行良好:

      class Chess  {
        constructor() {
          this.board = {}
          for (var i=0; i<8; i++) {
                for (var j=0; j<8; j++) {
                     this.board[i,j] = new Square(i,j)
                     }
                }
      
        };
      
      };
      
      class Square {
          constructor(row, col) {
            this.row = row;
            this.col = col;
            this.color = "black"
            if ((row+col)%2 == 1) this.color = "white"
        };
      };
      

      这两个独立的类在 Chess(主?)类中相互关联,并直接调用 Square 类,因此在 Chess 实例化时,棋盘方格也被定义。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-05-20
        • 1970-01-01
        • 1970-01-01
        • 2010-10-30
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多