Object.watch () для всех браузеров?


118

Обратите внимание, что Object.Watchи Object.Observeоба являются устаревшими (по состоянию на июнь 2018 г.).


Я искал простой способ отслеживать изменения объекта или переменной и обнаружил Object.watch(), что он поддерживается браузерами Mozilla, но не IE. Так что я начал искать, не написал ли кто-нибудь что-нибудь эквивалентное.

Единственное, что я нашел, это плагин jQuery , но я не уверен, что это лучший способ. Я, конечно, использую jQuery в большинстве своих проектов, поэтому меня не беспокоит аспект jQuery ...

В любом случае, вопрос: может ли кто-нибудь показать мне рабочий пример этого плагина jQuery? У меня проблемы с его работой ...

Или кто-нибудь знает какие-нибудь лучшие альтернативы, которые будут работать в кросс-браузере?

Обновление после ответов :

Спасибо всем за ответы! Я попробовал код, размещенный здесь: http://webreflection.blogspot.com/2009/01/internet-explorer-object-watch.html

Но я не мог заставить его работать с IE. Приведенный ниже код отлично работает в Firefox, но ничего не делает в IE. В Firefox каждый раз при watcher.statusизменении вызывается document.write()in, watcher.watch()и вы можете увидеть результат на странице. В IE этого не происходит, но я вижу, что watcher.statusпроисходит обновление значения, потому что последний document.write()вызов показывает правильное значение (как в IE, так и в FF). Но, если функция обратного вызова не вызывается, это бессмысленно ... :)

Я что-то упускаю?

var options = {'status': 'no status'},
watcher = createWatcher(options);

watcher.watch("status", function(prop, oldValue, newValue) {
  document.write("old: " + oldValue + ", new: " + newValue + "<br>");
  return newValue;
});

watcher.status = 'asdf';
watcher.status = '1234';

document.write(watcher.status + "<br>");

2
IIRC, вы можете использовать onPropertyChange в IE
scunliffe

1
Замените document.write () на alert (). Он должен работать нормально.
Ionuț G. Stan

Ответы:


113

(Извините за перекрестную публикацию, но этот ответ, который я дал на аналогичный вопрос, здесь отлично работает)

Некоторое время назад я создал для этого небольшую прокладку object.watch . Он работает в IE8, Safari, Chrome, Firefox, Opera и т. Д.


10
Объяснение того, как его использовать и как это работает внутри, было бы полезно для тех из нас, кто не является мастером JS, спасибо.
maraujop


jsfiddle.net/kSWxP ПОДСКАЗКА : используйте Firefox (последнее утверждение не печатается в Chrome)
Марс Робертсон


Я знал, что идея Object.defineProperty()существует. В итоге я посмотрел ссылку на MDN, чтобы узнать, как это работает.
jumpnett 04

19

Этот плагин просто использует таймер / интервал для многократной проверки изменений объекта. Может быть, достаточно хорошо, но лично я хотел бы больше непосредственности в качестве наблюдателя.

Вот попытка перенести watch/ unwatchв IE: http://webreflection.blogspot.com/2009/01/internet-explorer-object-watch.html .

Он действительно меняет синтаксис способа добавления наблюдателей в Firefox. Вместо того :

var obj = {foo:'bar'};
obj.watch('foo', fooChanged);

Вы делаете:

var obj = {foo:'bar'};
var watcher = createWatcher(obj);
watcher.watch('foo', fooChanged);

Не так мило, но как наблюдатель вы сразу же получите уведомление.


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

13

Ответы на этот вопрос немного устарели. Object.watch и Object.observe устарели и не должны использоваться.

Сегодня вы можете использовать объект Proxy для отслеживания (и перехвата) изменений, внесенных в объект. Вот простой пример:

var targetObj = {};
var targetProxy = new Proxy(targetObj, {
  set: function (target, key, value) {
      console.log(`${key} set to ${value}`);
      target[key] = value;
  }
});

targetProxy.hello_world = "test"; // console: 'hello_world set to test'

Если вам нужно наблюдать за изменениями, внесенными во вложенный объект, вам необходимо использовать специализированную библиотеку. Я опубликовал Observable Slim, и он работает так:

var test = {testing:{}};
var p = ObservableSlim.create(test, true, function(changes) {
    console.log(JSON.stringify(changes));
});

p.testing.blah = 42; // console:  [{"type":"add","target":{"blah":42},"property":"blah","newValue":42,"currentPath":"testing.blah",jsonPointer:"/testing/blah","proxy":{"blah":42}}]

12

Текущий ответ

Используйте новый объект Proxy , который может отслеживать изменения своей цели.

let validator = {
    set: function(obj, prop, value) {
        if (prop === 'age') {
            if (!Number.isInteger(value)) {
                throw new TypeError('The age is not an integer');
            }
            if (value > 200) {
                throw new RangeError('The age seems invalid');
            }
        }

        // The default behavior to store the value
        obj[prop] = value;

        // Indicate success
        return true;
    }
};

let person = new Proxy({}, validator);

person.age = 100;
console.log(person.age); // 100
person.age = 'young'; // Throws an exception
person.age = 300; // Throws an exception

Старый ответ от 2015 года

Вы могли использовать Object.observe () из ES7 . Вот полифилл. Но Object.observe () теперь отменен . Простите народ!


Хм, я не мог заставить этот полифилл работать на ios safari. Я получаю сообщение об ошибке: undefined не является функцией (оценка 'Object.observe (a.imgTouch, function (a) {console.debug ("lastX:" + a)})')
infomofo

@infomofo Привет, не хотели бы вы открыть вопрос на странице проекта со всеми подробностями, которые вы можете сообщить? Я не тестировал его на iOS, но постараюсь разобраться в проблеме.
MaxArt

6

Обратите внимание, что в Chrome 36 и выше вы также можете использовать Object.observe. Фактически это часть будущего стандарта ECMAScript, а не специфическая для браузера функция, такая как Mozilla Object.watch.

Object.observeработает только со свойствами объекта, но намного более производительно, чем Object.watch(который предназначен для целей отладки, а не для производственного использования).

var options = {};

Object.observe(options, function(changes) {
    console.log(changes);
});

options.foo = 'bar';

1
Как и в 2018 году, это устарело и больше не поддерживается всеми основными браузерами
Сергей Панфилов

4

вы можете использовать Object.defineProperty .

смотреть собственность barвfoo

Object.defineProperty(foo, "bar", {
  get: function (val){
      //some code to watch the getter function
  },

  set: function (val) {
      //some code to watch the setter function
  }
})

Это круто! Но я бы доработал его abit :) Чтобы не перезаписывать оригинальный сеттер. Я бы сделал ссылку foo._someObject = foo.someObject
calmbird

простой и
элегантный

1

Я использовал Watch.js в одном из своих проектов. И она работает нормально. Одно из главных преимуществ использования этой библиотеки:

«С Watch.JS вам не придется менять способ разработки».

Пример приведен ниже

//defining our object however we like
var ex1 = {
	attr1: "initial value of attr1",
	attr2: "initial value of attr2"
};

//defining a 'watcher' for an attribute
watch(ex1, "attr1", function(){
	alert("attr1 changed!");
});

//when changing the attribute its watcher will be invoked
ex1.attr1 = "other value";
<script src="https://cdn.jsdelivr.net/npm/melanke-watchjs@1.5.0/src/watch.min.js"></script>

Это так просто!


Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.