Замена прокси для ES5

#javascript #object #ecmascript-5 #es5-compatiblity

#javascript #объект #ecmascript-5 #es5-совместимость

Вопрос:

Возможно ли прослушивать изменения свойств без использования Proxy и setInterval ?

Для обычных объектов вы могли бы использовать приведенную ниже функцию, но это работает для всех существующих свойств, но не работает ни для каких свойств, которые могут быть добавлены после переноса.

 function wrap(obj) {
  var target = {};
  Object.keys(obj).forEach(function(key) {
    target[key] = obj[key];
    Object.defineProperty(obj, key, {
      get: function() {
        console.log("Get");
        return target[key];
      },
      set: function(newValue) {
        console.log("Set");
        target[key] = newValue;
      }
    });
  });
}

var obj = {
  a: 2,
  b: 3
};
wrap(obj);

obj.a; // Get
obj.a = 2; // Set
obj.b; // Get
obj.b = 2; // Set
obj.c = 2; // Nothing
obj.c; // Nothing  

Если объект представляет собой массив, вы также можете прослушать length свойство и сбросить все get и set функции при его изменении. Очевидно, что это не очень эффективно, поскольку изменяет свойства каждого элемента всякий раз, когда элемент добавляется или удаляется.

Так что я не думаю, что это Object.defineProperty правильный ответ.

Причина, по которой я не хочу использовать setInterval , заключается в том, что наличие больших интервалов сделает перенос ненадежным, тогда как наличие небольших интервалов окажет большое влияние на эффективность.

Комментарии:

1. Нет, вы не можете этого сделать в ES5.

2. @Bergi Как одностраничные приложения, такие как angular, делают это? setInterval ?

3. В старые времена? Да, я так думаю, тайм-аут или явный запуск грязной проверки.

4. по сути, вам нужно использовать $http предоставленный angular, который обертывает http-вызовы для выполнения дайджеста в конце. У них также есть $timeout и $interval для аналогичных с setTimeout и setInterval . Когда вы создаете фреймворк, подобный этому, вам нужно использовать все методы, предоставляемые в framework, или вы можете вызвать $scope.$digest() , чтобы запустить дайджест вручную, если вы делаете что-то за пределами «angular»

5. Angularjs следует чему-то, называемому a dirty check , которое в основном выполняет итерацию по их списку, watchers начиная rootScope со всех дочерних областей и сравнивая, изменилось ли scope значение. Это происходит постоянно в фоновом режиме, и каждый запуск вызывается digest cycle . Их внутренняя структура может стать действительно сложной, поэтому всегда рекомендуется использовать их методы-оболочки (например: $timeout instead of setTimeout )

Ответ №1:

К сожалению, нет, именно поэтому прокси были такой важной вещью. На данный момент нет другого способа запустить код при добавлении свойства к объекту, кроме Прокси.

Как вы говорите, вы можете использовать Object.defineProperty или var a = { get x() {...}, set x(value) {...} } , но не обнаруживать новые свойства.


Большинство фреймворков полагаются на грязную проверку: сравнение объектов по заданному времени. Разница главным образом во времени.

AngularJS (Angular 1.x) предоставил вам специальные функции для асинхронных операций, таких как $timeout и $http , и это собственный способ прослушивания событий DOM, которые завершат ваши обратные вызовы и запустят проверку после вашего кода.

Angular (от Angular 2 до N) используетZone.js чтобы создать «контекст выполнения» для вашего кода, любой асинхронный обратный вызов перехватывается Zone.js . По сути, это то же решение, что и для AngularJS, но работает автоматически.

React делает нечто подобное, но вместо отслеживания ваших переменных он запускает средство визуализации и сравнивает, отличается ли сгенерированный DOM (виртуальный DOM).