[] 覆盖 class 访问权限

Overriding class access by []

如果我有自己的自定义矩阵 class,我如何通过括号定义对它的访问?比如我怎样才能实现:

const matrix = new Matrix(2,2)
matrix[0, 0] = 1
matrix[0, 1] = 2
matrix[1, 0] = 3
matrix[1, 1] = 4
console.log(matrix[1, 1]) // prints 4.

// or...

matrix[0][0] = 1
matrix[0][1] = 2
matrix[1][0] = 3
matrix[1][1] = 4
console.log(matrix[1][1]) // prints 4.

,假设 new Matrix(2,2) 包含一个二维未初始化数组。

...how can I define access to it by brackets

你不能,以你所展示的方式。 JavaScript 没有相应的语法;相反,它有逗号运算符,它不会做你想要的。 0, 11, 1 都计算为 1 因为逗号运算符接受两个操作数,计算 left-hand 操作数,丢弃该值,然后计算 right-hand 操作数并将该结果作为逗号运算符的结果。所以 matrix[0, 1]matrix[1].

相反,定义一个接受两个参数的方法,并调用它 (matrix.at(0, 1)),或者使用数组数组并执行 matrix[0][1].

可以 通过使用 Proxy object and then parsing the string in the get and set 陷阱接受字符串 matrix["0,1"],但我怀疑这不适合你的用例(或大多数其他)。


你说过矩阵的宽高是在构造函数中设置的。您可以将您的字段存储在数组中(可能是类型化数组的数组,具体取决于您在矩阵中存储的内容)并为 0height - 1 定义属性以获取该行的数组。所以 matrix[0] 将是矩阵的第一行作为数组/类型数组,所以 matrix[0][0] 将是第一行的第一个单元格。这是一个非常基本的例子:

class Matrix {
    constructor(height, width) {
        this.data = Array.from(
            {length: height},
            () => Array.from({length: width}).fill(0)
        );
        for (let y = 0; y < height; ++y) {
            Object.defineProperty(this, y, {
                value: this.data[y]
            });
        }
    }
    toString() {
        return this.data.map(row => row.join(",")).join("\n");
    }
}

const m = new Matrix(5, 5);
m[1][2] = 1;
console.log(m.toString());

我在那里使用了 defineProperty,因为我认为我们不希望任何人写信给这些。通过不提供任何标志(writableconfigurableenumerable),我们采用所有默认值,即 false.

或者(比如)每行一个 Uint8Array

class Matrix {
    constructor(height, width) {
        this.data = Array.from(
            {length: height},
            () => Uint8Array.from({length: width}).fill(0)
// Only change is ^^^^^^^^^^
        );
        for (let y = 0; y < height; ++y) {
            Object.defineProperty(this, y, {
                value: this.data[y]
            });
        }
    }
    toString() {
        return this.data.map(row => row.join(",")).join("\n");
    }
}

const m = new Matrix(5, 5);
m[1][2] = 1;
console.log(m.toString());