【问题标题】:Object.watch() for all browsers?Object.watch() 适用于所有浏览器?
【发布时间】:2010-11-04 23:32:17
【问题描述】:

请注意,Object.WatchObject.Observe 现在都已弃用(截至 2018 年 6 月)。


我一直在寻找一种简单的方法来监视对象或变量的变化,我找到了Object.watch(),它在 Mozilla 浏览器中受支持,但在 IE 中不受支持。所以我开始四处寻找,看看是否有人写过类似的东西。

我发现的唯一东西是a jQuery plugin,但我不确定这是否是最好的选择。我当然在我的大部分项目中都使用 jQuery,所以我并不担心 jQuery 方面...

不管怎样,问题是:有人可以给我看一个该 jQuery 插件的工作示例吗?我在使它工作时遇到问题......

或者,有没有人知道可以跨浏览器工作的更好的替代方案?

回答后更新

感谢大家的回复!我尝试了这里发布的代码: http://webreflection.blogspot.com/2009/01/internet-explorer-object-watch.html

但我似乎无法使其与 IE 一起使用。下面的代码在 Firefox 中运行良好,但在 IE 中没有任何作用。在Firefox中,每次更改watcher.status,都会调用watcher.watch()中的document.write(),您可以在页面上看到输出。在 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>");

【问题讨论】:

  • IIRC 你可以在 IE 中使用 onPropertyChange
  • 将 document.write() 替换为 alert()。它应该可以正常工作。

标签: javascript jquery dom-events


【解决方案1】:

这个问题的答案有点过时了。 Object.watchObject.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}}]

【讨论】:

    【解决方案2】:

    我在我的一个项目中使用了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";
    &lt;script src="https://cdn.jsdelivr.net/npm/melanke-watchjs@1.5.0/src/watch.min.js"&gt;&lt;/script&gt;

    就这么简单!

    【讨论】:

      【解决方案3】:

      当前答案

      使用新的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() from ES7Here's a polyfill. 但是Object.observe() is now cancelled。对不起大家!

      【讨论】:

      • 嗯,我无法让这个 polyfill 在 ios safari 上工作。我得到错误:未定义不是一个函数(评估 'Object.observe(a.imgTouch,function(a){console.debug("lastX: "+a)})')
      • @infomofo 嗨,您想在项目页面上打开一个问题,并提供您可以提供的所有详细信息吗?我还没有在 iOS 上测试过,但我会调查一下问题。
      【解决方案4】:

      你可以使用Object.defineProperty

      foo 中关注bar 的属性

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

      【讨论】:

      • 这太棒了!但我会修改它 :) 不覆盖原来的二传手。我会参考 foo._someObject = foo.someObject
      • 简洁优雅
      【解决方案5】:

      请注意,在 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';
      

      【讨论】:

      • 与 2018 年一样,所有主流浏览器都已弃用,不再支持
      【解决方案6】:

      我也认为目前最好的解决方案是使用 Watch.JS,在这里找到一个不错的教程:Listen/Watch for object or array changes in Javascript (Property changed event on Javascript objects)

      【讨论】:

        【解决方案7】:

        (对不起,交叉发布,但我对类似问题的回答在这里可以正常工作)

        不久前我为此创建了一个小object.watch shim。它适用于 IE8、Safari、Chrome、Firefox、Opera 等。

        【讨论】:

        【解决方案8】:

        该插件仅使用计时器/间隔来重复检查对象的更改。也许足够好,但我个人希望作为观察者更直接。

        这里尝试将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 还在帖子中添加了更多信息,即使它是同一个链接。同时,我尝试了在该页面上找到的代码,但仍然发现问题。不过,我可能忽略了一些东西。我已经用更多信息更新了我的原始帖子...
        猜你喜欢
        • 2023-03-13
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-08-26
        • 2012-05-23
        • 2015-09-29
        • 2012-03-15
        • 2016-10-13
        相关资源
        最近更新 更多