Javascript обозреватель или прокси без каких-либо изменений, проходящих через прокси
Я пишу подкласс массивов в 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 было присуще моей функциональности класса.
То, что я действительно хочу, это способ перегрузки базовых методов, таких как []
а-ля C#, так что функции, которые выполняют обновление, будут запускать это без изменения синтаксиса, но я смирился с тем, что в JS этого нет.
1 ответ
Хотя прокси будет работать, он также будет работать довольно медленно. Для каждого метода, который должен использовать значение _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());