javascript - 类中类?

标签 javascript class oop nested

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

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 的建议,我做了以下事情:

我向 Class 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);

最佳答案

有人可能会争辩说 JavaScript 没有这样的“嵌套”类——例如,类无法使用父类作用域,除了访问父类属性(static 元素)。

JavaScript 中的类就像任何其他对象一样只是一个对象,因此您也可以定义一个对象并使用另一个类的属性来引用它:

class Chess {
}

Chess.Square = class {
};

(是的,类的名称是可选的——在上面,Chess 上的 Square 属性引用了一个没有名称的类;不一定非常适合调试和自省(introspection),只是在这里说明一点)

有了上面的内容,您可以执行以下操作:

new Chess.Square();

通常,您对类或类的对象所做的所有其他事情 -- new 只是期望一个函数充当构造函数,而 class 声明实际上是“程序运行时“衰减”到构造函数中——以下所有表达式的值都为真:

Chess instanceof Function;
typeof Chess == "function";
Chess.Square instanceof Function;
typeof Chess.Square == "function";
Chess.prototype.constructor == Chess;
Chess.Square.prototype.constructor == Chess.Square;

那么嵌套构造函数,那么——既然我们已经确定 JavaScript 类本质上就是它的构造函数。好吧,通过 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 中,上面指定的 Square 类被称为嵌套的 instance 类,而不是嵌套的 static 类。答案最顶部的第一个示例使用 class 关键字,但确实指定了后者的一种形式(“静态”类)。

这是另一种定义“实例”类 Square 的方法:

class Chess {
    constructor() {
        this.Square = class {
            constructor() {
                /// Be vigilant about `this` though -- in every function (except arrow functions) `this` is re-bound, meaning `this` in this constructor refers to an instance of the anonymous class, not to an instance of the `Chess` class; if you want to access the latter instance, you must have a reference to it saved for this constructor to access, e.g. with the `const chess = this;` statement in `Chess` constructor somewhere
            }
        }; /// Every `Chess` object gets a _distinct_ anonymous class referred to with a property named `Square`; is a class for every object expensive? is it needed? is it useful?
    }
}

关于 JavaScript 的事情是,无论好坏,它使得以不止一种方式实现 OOP 成为可能,当然比其他一些“OOP 语言”所允许的方式更多,并且“嵌套类”可以对不同的人和不同的程序意味着不同的事情。这被称为“有很多绳子可以吊死自己”——很多设施可以帮助您优雅地实现您的预​​期模型,和/或使您的代码难以阅读(尤其是对于那些不知道的人和你一样多的 JavaScript)和调试。这是在使用“嵌套类”之前需要解决的权衡问题。

关于javascript - 类中类?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53448096/

相关文章:

javascript - 通过鼠标单击场景来模拟 2d js Canvas 上的物理 3d 球 throw

PHP - 只接受特定类的数组

class - Core Data NSPredicate 按实体类过滤?

可以在项目的任何文件中使用的C++变量

java - 面向对象编程——两种方式组合练习?

java - 方法实现后通用方法的接口(interface)

javascript - 在 Canvas 上随机绘制图像 x 和 y

java - 如何将 Javascript 中的日期与语言环境进行比较

javascript - 命名空间,OOP JS,我这样做对吗?

javascript - 如何在对象方法上调用requestAnimFrame?