#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).