Monitoring Javascript Data w/ Proxies

by Thomas Urban

One of the most awesome features of ECMAScript 6 is the support for proxies. With instances of Proxy you can monitor any object for detecting when code is changing it. Of course, there are other use cases for new class Proxy. And monitoring objects was somewhat possible before by using more complex code replacing properties of any observed object with getters and setters and detecting additional properties on demand. That approach wasn't available with arrays due to their special semantics. Using proxies this whole monitoring becomes a lot easier.

Here comes a very small function available for monitoring some arbitrary object or array:

function monitor( object ) {
let handlers = {
ctx: {
changed: new Set(),
},
get: _get,
set: _set,
};

return new Proxy( object, handlers );
}

Properties get and set of handlers are referring to implementations moved out of scope of function monitor(). This is assuring to use same instance of either function each time some object gets observed. Declaring these functions in monitor() would result in separate instances of either function on either monitored object due to different closure scopes on every invocation of monitor().

function _get( target, name ) {
if ( name === "$context" ) {
return this.ctx;
}

return target[name];
}

function _set( target, name, value ) {
console.log( this, arguments );

// pass actual action
target[name] = value;

if ( name !== "$context" ) {
// track change
this.ctx.changed.add( name );

return true;
}

return false;
}

Monitoring an array (or any other object) becomes as easy as this:

let raw = [ "test" ];

let monitor1 = monitor( raw );
let monitor2 = monitor( raw );

raw.push( "hi!" );

monitor1.push( "ho!" );

monitor2.push( "hey!" );
monitor2.splice( 1, 1 );

console.log( "monitored data:", raw );

console.log( "context of monitor1:", monitor1.$context );
console.log( "context of monitor2:", monitor2.$context );
console.log( monitor1.$context === monitor2.$context );

monitor1.$context.changed.clear();

console.log( "context of monitor1:", monitor1.$context );
console.log( "context of monitor2:", monitor2.$context );

monitor1.$context = { different: "object" };

This results in logging on your browser's Javascript console (or stdout in case of using NodeJS) similar to this one:

Go back