public
Created

Object.prototype.watch that is closer to complete (to existing Firefox implementation)

  • Download Gist
object-watch.js
JavaScript
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120
!function(){
if (Object.prototype.watch) return;
 
var FP = Function.prototype;
var bindbind = FP.bind.bind(FP.bind),
callbind = bindbind(FP.call),
 
bind = callbind(FP.bind),
call = callbind(FP.call),
 
hasOwn = callbind(Object.prototype.hasOwnProperty);
 
var define = Object.defineProperty,
describe = Object.getOwnPropertyDescriptor,
names = Object.getOwnPropertyNames;
 
 
var getName = function(){
if ('name' in Function.prototype)
return function getName(f){
return f.name;
};
else
return function getName(f){
var src = (f+'');
return src.slice(9, src.indexOf('('));
};
}();
 
function defineMethod(o, f){
define(o, getName(f), {
configurable: true,
writable: true,
value: f
});
}
 
var _ = function(){
var uid = '_'+Math.random().toString(36).slice(2);
 
defineMethod(Object, function getOwnPropertyNames(o){
var out = names(o);
if (hasOwn(o, uid))
out.splice(out.indexOf(uid), 1);
return out;
});
 
return function _(o){
if (!hasOwn(o, uid))
define(o, uid, { value: Object.create(null) });
return o[uid];
};
}();
 
function getPropertyDescriptor(o, prop){
var desc;
while (o && !(desc = describe(o, prop)))
o = Object.getPrototypeOf(o);
return desc;
}
 
defineMethod(Object, function defineProperty(o, prop, desc){
var self = _(o);
if (prop in self)
self[prop] = desc;
else
define(o, prop, desc);
});
 
defineMethod(Object, function defineProperties(o, descs){
for (var k in descs)
Object.defineProperty(o, k, descs[k]);
});
 
defineMethod(Object, function getOwnPropertyDescriptor(o, prop){
var self = _(o);
if (prop in self)
return self[prop];
else
return describe(o, prop);
});
 
defineMethod(Object.prototype, function watch(prop, handler){
var self = _(this);
var rcvr = this;
var desc = self[prop] = self[prop] || getPropertyDescriptor(this, prop) || {
enumerable: true,
configurable: true,
writable: true,
value: undefined
};
 
if (desc.configurable) {
define(this, prop, {
get: function(){
return typeof desc.get === 'function' ? call(desc.get, this) : desc.value;
},
set: function(v){
if (typeof desc.set === 'function')
call(desc.set, this, call(handler, this, prop, desc.value, v));
else if (rcvr !== this)
define(this, prop, { enumerable: true, configurable: true, writable: true, value: v });
else
desc.value = call(handler, this, prop, desc.value, v);
},
enumerable: desc.enumerable,
configurable: true
});
}
});
 
defineMethod(Object.prototype, function unwatch(prop){
var self = _(this);
if (prop in self) {
define(this, prop, self[prop]);
delete self[prop];
}
});
 
}();
testing-object-watch.js
JavaScript
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
var x = function(o){
return {
get y(){ return o * 2 },
set y(v){ o = v },
z: 10
};
}();
 
 
function watcher(prop, oldVal, newVal){
console.log('x.'+prop, oldVal, newVal);
return newVal;
}
 
x.watch('y', watcher);
x.watch('z', watcher);
 
x.y = 20;
x.z = 100;
 
var x2 = Object.create(x);
 
x2.y = 100;
x2.z = 200;
 
console.log(x)
console.log(x2)

Please sign in to comment on this gist.

Something went wrong with that request. Please try again.