【问题标题】:How to detect when a property is added to a JavaScript object?如何检测属性何时添加到 JavaScript 对象?
【发布时间】:2012-10-01 18:02:13
【问题描述】:
var obj = {};
obj.a = 1; // fire event, property "a" added 

这个问题与this one 不同,后者正在讨论检测已声明属性何时更改的方法。

【问题讨论】:

  • 当前的 ECMAScript 标准中没有任何内容,但下一个标准可能会实现一个名为 Proxy 的功能,该功能将提供此功能。 Firefox 已经实现了这一点。
  • 相关:Object.watch - 仅适用于选定的属性
  • @Bergi:两篇文章都提到了检测已经声明的给定 JavaScript 对象的属性更改的方法。已接受答案的库(Watch.js 或较新的 MultiGetSet.js)允许您通过仅调用一种方法来查看 JavaScript 对象的属性(因此在这里很方便),但此库不考虑“当您添加此对象的新属性和/或更改它,观察者将不会被调用”(取自 Watch.js gist)。我想检测何时将新属性添加到 JavaScript 对象(检测新属性的值变化是第二个)。
  • @Scholle: 不,my answer 在副本上处理检测对象上的任何属性更改

标签: javascript


【解决方案1】:

这在技术上是可能的,但由于我所知道的所有当前 JS 实现都是单线程的,所以它不会很优雅。我唯一能想到的就是蛮力间隔:

var checkObj = (function(watchObj)
{
    var initialMap = {},allProps = [],prop;
    for (prop in watchObj)
    {
        if (watchObj.hasOwnProperty(prop))
        {//make tracer object: basically clone it
            initialMap[prop] = watchObj[prop];
            allProps.push(prop);//keep an array mapper
        }
    }
    return function()
    {
        var currentProps = [];
        for (prop in watchObj)
        {
            if (watchObj.hasOwnProperty(prop))
            {//iterate the object again, compare
                if (watchObj[prop] !== initialMap[prop])
                {//type andvalue check!
                    console.log(initialMap[prop] + ' => ' watchObj[prop]);
                    //diff found, deal with it whichever way you see fit
                }
                currentProps.push(prop);
            }
        }
        //we're not done yet!
        if (currentProps.length < allProps.length)
        {
            console.log('some prop was deleted');
            //loop through arrays to find out which one
        }
    };
})(someObjectToTrack);
var watchInterval = setInterval(checkObj,100);//check every .1 seconds?

这使您可以在一定程度上跟踪对象,但同样,要以 10 秒/秒的速度完成这项工作需要做很多工作。谁知道呢,也许对象在间隔之间也发生了几次变化。
总而言之,我觉得这似乎是一种不太理想的方法......也许比较字符串常量会更容易JSON.stringify'ed 对象,但这确实意味着错过了函数,并且(尽管我在本例中将它们过滤掉了)原型属性。

我曾经考虑过做类似的事情,但最终只是使用我的事件处理程序更改了相关对象来检查任何更改。
或者,您也可以尝试创建一个 DOMElement,并将 onchange 侦听器附加到它...遗憾的是,函数/方法可能难以跟踪,但至少它不会像上面的代码会。

【讨论】:

    【解决方案2】:

    你可以计算对象的属性,看看你上次检查时是否发生了变化:

    How to efficiently count the number of keys/properties of an object in JavaScript?

    这是一个粗略的解决方法,以防您在语言中找不到对该功能的适当支持。

    【讨论】:

    • 我明白了你的意思,但你怎么知道何时计算房产数量?运行循环是不可接受的,尤其是在浏览器环境中。
    • 一个 setInterval() 时间间隔适合您的需要。
    • 次优,你可能有很多对象,设置一个 setInterval() 并运行一个计算属性的函数,并且可以选择确定添加了哪个属性,每一个每秒几次,听起来不健康。另外,setInterval()在浏览器中显然不是阻塞的,但是注册在setInterval()上的函数的执行可能会被推迟。
    • 投票 - 这很容易适应@Elias Van Ootegem 的回答。而不是for(var key in object) 循环,只需检查Object.keys(object).length。为什么@Nelson 的答案应该被否决???
    • 删除obj.prop1; obj.prop2 = 'xyz';计数保持不变。
    【解决方案3】:

    如果性能很重要并且您可以控制更改对象的代码,请创建一个控制类来为您修改对象,例如

    var myObj = new ObjectController({});
    
    myObj.set('field', {});
    myObj.set('field.arr', [{hello: true}]);
    myObj.set('field.arr.0.hello', false);
    
    var obj = myObj.get('field'); // obj === {field: {arr: [{hello: false}]}}
    

    在您的 set() 方法中,与设置间隔和定期扫描以检查更改相比,您现在能够以相当高性能的方式查看每次更改发生的位置。

    我在 ForerunnerDB 中做了类似但高度优化的事情。当您对数据库执行 CRUD 操作时,会针对特定字段路径触发更改事件,从而允许在其基础数据更改时更新数据绑定视图。

    【讨论】:

      猜你喜欢
      • 2011-02-16
      • 1970-01-01
      • 1970-01-01
      • 2015-11-15
      • 2021-03-15
      • 1970-01-01
      • 2011-11-23
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多