Javascript обозреватель или прокси без каких-либо изменений, проходящих через прокси - PullRequest
0 голосов
/ 16 января 2019

Я пишу подкласс массивов в Javascript для лучшей поддержки матричных операций (я знаю, что существуют другие, это частично для меня, чтобы заново учить себя линейной алгебре), и я хочу иметь некоторые свойства, которые сбрасываются всякий раз, когда какие-либо значения в матрице корректируются. Некоторые вычисления, такие как определитель, требуют значительных вычислительных ресурсов, и я хотел бы иметь возможность сохранить их, чтобы избежать повторного вычисления, но затем их необходимо сбросить на ноль при каждом изменении каких-либо матричных элементов.

По сути, мне кажется, что я хочу устаревший Array.observe () . И замена прокси, кажется, требует много времени для этого. Как упоминалось в некоторых комментариях к Обнаружение изменений в массиве Javascript с использованием прокси-объекта , которые не были адресованы напрямую, я не хочу получать доступ к моим матрицам только через прокси. Я использую много удобных [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] = 10 или mat.push([2,4,5]), которое обновляет значения в матрице для установки mat._determinant = null. Или любой эквивалентный метод пометки, что его нужно пересчитать в следующий раз, когда его запрашивают. Я не против использования прокси обязательно, если кто-то может помочь мне разобраться в реализации, я просто предпочел бы, чтобы это свойство set-to-null-on-update было присуще моей функциональности класса.

Что мне действительно нужно, так это способ перегружать базовые методы, такие как [] a la C #, поэтому функции, выполняющие обновление, будут вызывать это без изменения синтаксиса, но я смирился с тем, что в JS этого нет.

1 Ответ

0 голосов
/ 16 января 2019

Хотя прокси будет работать, он также будет работать довольно медленно. Для каждого метода, который должен использовать значение _determinant, будет использоваться другой подход: сначала выполните другую функцию, чтобы проверить, нужно ли обновлять _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());
...