Как я могу вызвать обратный вызов при изменении атрибута объекта? - PullRequest
4 голосов
/ 27 апреля 2020

Если у меня есть такой класс:

class Myclass {
    constructor(){
        this.a = [];
        this.sum = 0;
    }

    update(){
       this.sum = this.a.reduce((a, b) => a + b, 0)
    }
}

Я создаю экземпляр класса:

myClass = new Myclass();

Я добавляю число к атрибуту a

myClass.a.push(1);
myClass.a.push(2);

Как я могу вызывать метод обновления каждый раз, когда изменяется атрибут a? Другими словами, как я могу вызвать обратный вызов при изменении атрибута объекта?

Ответы [ 4 ]

7 голосов
/ 27 апреля 2020

Добавить метод для добавления новых элементов в массив a, например:

class Myclass {
    constructor(){
        this.a = [];
        this.sum = 0;
    }

    update(){
       this.sum = this.a.reduce((a, b) => a + b, 0)
    }

    pushItem(val) {
        this.a.push(val);
        this.update();
    }

}

myClass = new Myclass();
myClass.pushItem(1);
myClass.pushItem(2);
console.log(myClass.sum);
3 голосов
/ 27 апреля 2020

Одним из способов является расширение Array и создание тени для метода push.

class MyArray extends Array{
  constructor(ref){
    super();
    this.ref = ref
  }
  push(value){
    super.push(value)
    this.ref.update()
    console.log("called")
  }
}

class Myclass {
    constructor(){
        this.a = new MyArray(this);
        this.sum = 0;
    }
   
    update(){
       this.sum = this.a.reduce((a, b) => a + b, 0)
    }
}

let myClass = new Myclass()
myClass.a.push(1);
myClass.a.push(2);

console.log(myClass.sum)

PS: - Конечно, не стоит вызывать обратный вызов при каждой вставке, если вы не используете значение суммы после вставки.

1 голос
/ 27 апреля 2020

Другими словами, как я могу вызвать обратный вызов при изменении атрибута объекта?

Это общее решение вышеуказанного вопроса. Если вам нужно решение для конкретного случая использования c только для массива a, игнорируйте это.

Проверьте Прокси ES6 для чего-то более мощного, чем простые методы получения / установки для получения / установить перехват. Возможно, вы захотите рекурсивно обернуть прокси, поскольку у вас есть вложенная структура данных. Примерно так:

function wrapWithProxyCallback(obj, callback) {
  return new Proxy(obj, {
    get (target, key, receiver) {
      const result = Reflect.get(target, key, receiver)
      // wraps nested data with Proxy
      if (typeof result === 'object' && result !== null) {
        return wrapWithProxyCallback(result, callback)
      }
      return result
    },
    set (target, key, value, receiver) {
      // calls callback on every set operation
      callback(target, key, value /* and whatever else you need */)
      return Reflect.set(target, key, value, receiver)
    }
  })
}

И использовать это как:

const wrappedClass = wrapWithCallback(
  myClass,
  (target, key) => console.log(target[key])
)

// this will call the above callback
wrappedClass.a.push(1);

Это немного наивно, но хорошая общая отправная точка. Возможно, вы захотите проверить, не вложены ли вложенные данные, например, в Прокси.

Что вы хотите сделать, это, вероятно, правильно настроить выравнивание с прозрачной реактивностью (хотя я должен был бы увидеть содержимое вашего обратного вызова, чтобы быть уверенным в этом. Я думаю, вы должны проверить mobx или @ nx-js / наблюдатель-утилита (последний автор - я) для готовых коробочных решений.

Редактировать: Мой первый пример вызвал обратный вызов при операциях get, Я исправил это для запуска на множестве операций.

0 голосов
/ 27 апреля 2020

Может быть, организовав объект как

class Myclass {
    constructor(){
        this.a = [];
    }

    get sum(){
       return this.a.reduce((a, b) => a + b, 0)
    }
}

Если я не ошибаюсь, вызов myClass.sum вернет сумму значений в массиве, хранящемся в атрибуте a.

...