Skip to content

Instantly share code, notes, and snippets.

@kevincennis
Last active August 29, 2015 14:14
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kevincennis/e5824f51728d52e6f8c8 to your computer and use it in GitHub Desktop.
Save kevincennis/e5824f51728d52e6f8c8 to your computer and use it in GitHub Desktop.
Proxy Model
var EventEmitter = (function() {
var cache = new WeakMap();
function EventEmitter( obj ) {
cache.set( this, {} );
}
EventEmitter.prototype = {
on: function( evt, fn ) {
var hash = cache.get( this );
( hash[ evt ] || ( hash[ evt ] = [] ) ).push( fn );
return this;
},
emit: function( evt ) {
var args = Array.prototype.slice.call( arguments, 1 ),
events = cache.get( this )[ evt ],
len, i;
if ( events ) {
for ( i = 0, len = events.length; i < len; ++i ) {
events[ i ].apply( this, args );
}
}
return this;
},
off: function( evt, fn ) {
var hash = cache.get( this ),
events = hash[ evt ],
keep, len, i;
if ( !evt ) {
cache.set( this, {} );
}
else if ( events && !fn ) {
delete hash[ evt ];
}
else if ( events ) {
keep = [];
for ( i = 0, len = events.length; i < len; ++i ) {
if ( events[ i ] !== fn ) {
keep.push( events[ i ] );
}
}
hash[ evt ] = keep;
}
return this;
}
};
return EventEmitter;
}());
var model = new Model({
foo: 'bar',
method: function() {
console.log( this.foo );
}
});
model.on( 'change', function( key, val ) {
console.log( 'change:' + key, val );
});
model.bar = 'baz'; // emits 'change'
model.method(); // 'bar'
var Model = (function() {
var methods = [ 'on', 'off', 'emit' ],
proto = EventEmitter.prototype;
function Model( obj ) {
var bound = {};
obj = obj || {};
EventEmitter.call( obj );
return new Proxy( obj, {
get: function( obj, key ) {
var val;
// EventEmitter methods
if ( methods.indexOf( key ) !== -1 ) {
return bound[ key ] || ( bound[ key ] = proto[ key ].bind( obj ) );
}
val = obj[ key ];
// own methods
if ( typeof val === 'function' ) {
return bound[ key ] || ( bound[ key ] = val.bind( obj ) );
}
// non-function values
return val;
},
set: function( obj, key, val ) {
if ( methods.indexOf( key ) !== -1 ) {
throw new Error('Cannot override ' + key );
}
if ( obj[ key ] !== val ) {
obj[ key ] = val;
if ( typeof val === 'function' ) {
bound[ key ] = val.bind( obj );
}
proto.emit.call( obj, 'change', key, val );
}
return val;
}
});
}
return Model;
}());
@kevincennis
Copy link
Author

Firefox only, FYI.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment