A great article came out yesterday: Data-binding Revolutions with Object.observe()

If you didn’t read it yet, go read it then come back here.

Ok the basic idea of that article is that you can do things like this

var model = {}; // Which we then observe Object.observe(model, function(changes){ // This asynchronous callback runs and aggregates changes changes.forEach(function(change) { // Letting us know what changed console.log(change.type, change.name, change.oldValue); }); }); model.adding = 'a prop'; model.nested = { obj: 'thing' }; model.nested.obj = 'another thing';

running that in the console we get:

add adding undefined add nested undefined

Now it would be cool if there was a way to observe nested objects. Here’s a simple function to do so:

function observeNested(obj, callback) { Object.observe(obj, function(changes){ changes.forEach(function(change) { if (typeof obj[change.name] == 'object') { observeNested(obj[change.name], callback); } }); callback.apply(this, arguments); }); }

Now at first glance it would seem this doesn’t work:

function observeNested(obj, callback) { Object.observe(obj, function(changes){ changes.forEach(function(change) { if (typeof obj[change.name] == 'object') { observeNested(obj[change.name], callback); } }); callback.apply(this, arguments); }); } var model = {}; // Which we then observe observeNested(model, function(changes){ changes.forEach(function(change) { console.log(change.type, change.name, change.oldValue); }); }); model.adding = 'a prop'; model.nested = { obj: 'thing' }; model.nested.obj = 'another thing';

Still shows:

add adding undefined add nested undefined

But then I remembered that (and I’m quiting from the article): Object.observe(), part of a future ECMAScript standard, is a method for asynchronously observing changes to JavaScript objects

So in the case above since the two assignments to model.nested happen right after another, it only logs it as one event, If you were using promises to some other async mechanism it would work as advertised:

function observeNested(obj, callback) { Object.observe(obj, function(changes){ changes.forEach(function(change) { if (typeof obj[change.name] == 'object') { observeNested(obj[change.name], callback); } }); callback.apply(this, arguments); }); } var model = {}; // Which we then observe observeNested(model, function(changes){ changes.forEach(function(change) { console.log(change.type, change.name, change.oldValue); }); }); setTimeout(function() { model.adding = 'a prop'; }, 200); setTimeout(function() { model.nested = { obj: 'thing' }; }, 400); setTimeout(function() { model.nested.obj = 'another thing'; }, 600);

Which shows: