简体   繁体   中英

How to detect when a property is added to a JavaScript object?

var obj = {};
obj.a = 1; // fire event, property "a" added 

This question is different from this one , where ways to detect when an already declared property is changed, being discussed.

You could count the properties on the object and see if has changed from when you last checked:

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

this is a crude workaround, to use in case you can't find a proper support for the feature in the language.

this is possible, technically, but since all current JS implementations that I know of are single threaded it won't be very elegant. The only thing I can think of is a brute force interval:

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?

That allows you to track an object to some extent, but again, it's quite a lot of work to do this 10/sec. Who knows, maybe the object changes several times in between the intervals, too.
All in all, I feel as though this is a less-then-ideal approach... perhaps it would be easier to compare the string constants of the JSON.stringify 'ed object, but that does mean missing out on functions, and (though I filtered them out in this example) prototype properties.

I have considered doing something similar at one point, but ended up just using my event handlers that changed the object in question to check for any changes.
Alternatively, you could also try creating a DOMElement, and attach an onchange listener to that... sadly, again, functions/methods might prove tricky to track, but at least it won't slow your script down as much as the code above will.

If performance matters and you are in control of the code that changes the objects, create a control class that modifies your objects for you, eg

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}]}}

In your set() method, you now have the ability to see where every change occurs in a pretty high-performance fashion, compared with setting an interval and doing regular scans to check for changes.

I do something similar but highly optimised in ForerunnerDB. When you do CRUD operations on the database, change events are fired for specific field paths, allowing data-bound views to be updated when their underlying data changes.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM