Javascript观察器或代理,无需通过代理进行所有更改

时间:2019-01-16 02:24:14

标签: javascript arrays observers proxy-pattern

我正在用Javascript编写数组的子类,以更好地支持矩阵运算(我知道其他人也存在,部分原因是我重新学习了线性代数),而我想要的是拥有一些能只要调整矩阵中的任何值,就将重置。像行列式这样的一些计算是计算密集型的,我希望能够存储它们以避免重新计算,但是每当矩阵元素发生变化时,都需要将它们重置为null。

从本质上来说,似乎我想要的是已弃用的Array.observe()。替换,代理,似乎在这件事上要花很多钱。正如在Detecting Changes in a Javascript Array using the proxy object上的一些注释中未提到的那样,我不想仅通过代理访问我的矩阵。到目前为止,我在编写的代码中使用了许多方便的[i][j]索引和[mat[i], mat[j]] = [mat[j], mat[i]]

class Matrix extends Array {
  constructor() {
    var args  = [];
    for (var i = 0; i < arguments.length; i++) {
        if (Array.isArray(arguments[i])) {
        args.push(new Matrix(...arguments[i]));
      } else {
        args.push(arguments[i]);
      }
    }
    super(...args);
    this._determinant = null;
  }
  determ(forceRecalculate = false) {
    if (this._determinant === null || forceRecalculate) {
        this.upperEchelon();
    }
    return this._determinant;
  }
  upperEchelon(reduced = false) {
  //There's a lot of code here but in the process of doing this other thing
  //you get 99% of the way to calculating the determinant so it does this
  this._determinant = factor;
  }
}

基本上,我想要诸如mat[0][0] = 10mat.push([2,4,5])之类的东西来更新矩阵中的值以设置mat._determinant = null。或标记为下次需要重新计算的标记的任何等效方法。如果有人可以帮助我确定实现方式,我并不反对使用代理,我宁愿将此set-to-null-on-update属性作为类功能的固有属性。

我真正想要的是一种重载基础方法(如[] la C#)的方法,因此执行更新的函数将在不更改语法的情况下触发此方法,但是我已经辞职了,以免在JS中没有它。

1 个答案:

答案 0 :(得分:1)

尽管代理服务器可以工作,但它也非常慢。对于需要使用_determinant值的每种方法,一种不同的方法是首先通过 different 函数来检查是否需要更新_determinant(并且如果是这样,请对其进行更新)。这样,每次数组更改时都不会进行昂贵的重新计算,而只是及时使用结果。例如:

class Matrix extends Array {
  constructor() {
    var args  = [];
    for (var i = 0; i < arguments.length; i++) {
      if (Array.isArray(arguments[i])) {
        args.push(new Matrix(...arguments[i]));
      } else {
        args.push(arguments[i]);
      }
    }
    super(...args);
    this._determinant = null;
  }
  // next method is effectively a recursive deep join
  // could also use toString if it doesn't interfere with anything else
  getString() {
    const itemsStr = this.map((item) => (
    item instanceof Matrix
      ? item.getString()
      : item
    ))
    .join(',');
    const result = '[' + itemsStr + ']';
    return result;
  }
  getDeterm() {
    const newString = this.getString();
    if (newString !== this._lastString) {
      this._lastString = newString;
      this.upperEchelon();
    }
    return this._determinant;
  }
  upperEchelon() {
    console.log('running upperEchelon');
    this._determinant = Math.random();
  }
}

const m = new Matrix([2, 3, 4], 5);
console.log(m.getDeterm());
// Not calculated again:
console.log(m.getDeterm());
// Mutation, next call of getDeterm will run upperEchelon:
m[0][0] = 1;
console.log(m.getDeterm());