Skip to content

Instantly share code, notes, and snippets.

@arvindr21
Forked from riddy/object-watch.js
Created June 21, 2018 04:32
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 arvindr21/322e4da27e52c0babc43e8f4ca2ddcac to your computer and use it in GitHub Desktop.
Save arvindr21/322e4da27e52c0babc43e8f4ca2ddcac to your computer and use it in GitHub Desktop.
object.watch polyfill
/**
* DEVELOPED BY
* GIL LOPES BUENO
* gilbueno.mail@gmail.com
*
* LEARN HOW TO USE IT:
* http://watch.k6.com.br
* FORK:
* https://gist.github.com/1627705
*/
Object.prototype.watch = function() {
if (arguments.length == 1)
this.watchAll.apply(this, arguments);
else if (Array.isArray(arguments[0]))
this.watchMany.apply(this, arguments);
else
this.watchOne.apply(this, arguments);
}
Object.prototype.watchAll = function(watcher) {
var obj = this;
if (obj instanceof String || (!(obj instanceof Object) && !Array.isArray(obj))) //accepts only objects and array (not string)
return;
var props = [];
if(Array.isArray(obj)){
for (var prop=0; prop<obj.length; prop++) { //for each item if obj is an array
props.push(prop); //put in the props
}
}else{
for (var prop2 in obj) { //for each attribute if obj is an object
props.push(prop2); //put in the props
}
}
obj.watchMany(props, watcher); //watch all itens of the props
};
Object.prototype.watchMany = function(props, watcher) {
var obj = this;
if(Array.isArray(obj)){
for (var prop in props) { //watch each iten of "props" if is an array
obj.watchOne(props[prop], watcher);
}
}else{
for (var prop2 in props) { //watch each attribute of "props" if is an object
obj.watchOne(props[prop2], watcher);
}
}
};
Object.prototype.watchOne = function(prop, watcher) {
var obj = this;
var val = obj[prop];
if(obj[prop]===undefined || isFunction(obj[prop]) || prop == "watchers" || prop == "__proto__") //dont watch if it is null, is a function, named "watchers" or "__proto__"
return;
if(obj[prop]!=null)
obj[prop].watchAll(watcher); //recursively watch all attributes of this
obj.watchFunctions(prop);
if (!obj.watchers) {
obj.watchers = {};
}
if (!obj.watchers[prop])
obj.watchers[prop] = [];
obj.watchers[prop].push(watcher); //add the new watcher in the watchers array
var getter = function() {
return val;
};
var setter = function(newval) {
var oldval = val;
val = newval;
obj[prop].watchAll(watcher);
obj.watchFunctions(prop);
var oldvalAtr = oldval.attributes() || oldval;
var newvalAtr = newval.attributes() || newval;
if (JSON.stringify(oldvalAtr) != JSON.stringify(newvalAtr) && arguments.callee.caller != watcher) {
obj.callWatchers(prop);
}
};
if (Object.defineProperty) { // ECMAScript 5
Object.defineProperty(obj, prop, {
get: getter,
set: setter,
enumerable: true,
configurable: true
});
} else if (Object.prototype.__defineGetter__ && Object.prototype.__defineSetter__) { // legacy
Object.prototype.__defineGetter__.call(obj, prop, getter);
Object.prototype.__defineSetter__.call(obj, prop, setter);
}
};
Object.prototype.callWatchers = function(prop) {
var obj = this;
for (var wr in obj.watchers[prop]) {
if (isInt(wr)){
obj.watchers[prop][wr]();
}
}
};
Object.prototype.attributes = function(){
var obj = this;
var response;
if(obj instanceof Boolean || obj instanceof Number || obj instanceof String){
return obj;
}else if(Array.isArray(obj)){
response = [];
for (var prop=0; prop<obj.length; prop++) {
if(!obj[prop] || isFunction(obj[prop]) || prop == "watchers" || prop == "__proto__")
continue;
if(obj[prop].attributes)
response.push(obj[prop].attributes());
else
response.push(obj[prop]);
}
}else if(obj instanceof Object){
response = {};
for (var prop2 in obj) {
if(obj[prop2]===undefined || isFunction(obj[prop2]) || prop2 == "watchers" || prop2 == "__proto__")
continue;
if(obj[prop2] && obj[prop2].attributes)
response[prop2] = obj[prop2].attributes();
else
response[prop2] = obj[prop2];
}
}else{
return obj;
}
return response;
};
Object.prototype.watchFunctions = function(prop) {
var obj = this;
if(!obj[prop])
return;
if (!(obj[prop] instanceof String) && (Array.isArray(obj[prop]))) {//is array?
obj[prop].pop = (function() {
var original = Array.prototype.pop;
return function() {
var response = original.apply(this, arguments);
obj.watchOne(obj[prop]);
obj.callWatchers(prop);
return response;
};
})();
obj[prop].push = (function() {
var original = Array.prototype.push;
return function() {
var response = original.apply(this, arguments);
obj.watchOne(obj[prop]);
obj.callWatchers(prop);
return response;
};
})();
obj[prop].reverse = (function() {
var original = Array.prototype.reverse;
return function() {
var response = original.apply(this, arguments);
obj.watchOne(obj[prop]);
obj.callWatchers(prop);
return response;
};
})();
obj[prop].shift = (function() {
var original = Array.prototype.shift;
return function() {
var response = original.apply(this, arguments);
obj.watchOne(obj[prop]);
obj.callWatchers(prop);
return response;
};
})();
obj[prop].sort = (function() {
var original = Array.prototype.sort;
return function() {
var response = original.apply(this, arguments);
obj.watchOne(obj[prop]);
obj.callWatchers(prop);
return response;
};
})();
obj[prop].splice = (function() {
var original = Array.prototype.splice;
return function() {
var response = original.apply(this, arguments);
obj.watchOne(obj[prop]);
obj.callWatchers(prop);
return response;
};
})();
obj[prop].unshift = (function() {
var original = Array.prototype.unshift;
return function() {
var response = original.apply(this, arguments);
obj.watchOne(obj[prop]);
obj.callWatchers(prop);
return response;
};
})();
}
};
function isFunction(functionToCheck) {
var getType = {};
return functionToCheck && getType.toString.call(functionToCheck) == '[object Function]';
}
function isInt(x) {
var y = parseInt(x);
if (isNaN(y)) return false;
return x == y && x.toString() == y.toString();
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment