Last active
May 13, 2017 12:04
-
-
Save w3core/0483c70491ae23f6b457811b16f9ae36 to your computer and use it in GitHub Desktop.
Tiny crossbrowser recursive Object observer
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Recursive Object observer for all existing or passed properties | |
* | |
* Notes: | |
* 1. You can use `delete` operator for any of children properties but not for the top level watchable properties from `object` | |
* 2. The watcher will be applied for all existing properties of `object`. | |
* To apply watcher for one property please pass `name` of property as argument. | |
* | |
* @param handler {Function} handler(operation, key, val, old) | |
* @param object {Object} Optional | |
* @param name {String} Optional. The `name` of property in `object` that to be handled | |
* | |
* @returns {Object} | |
* | |
* @license MIT | |
* @author Max Chuhryaev | |
*/ | |
(function (global, factory) { | |
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : | |
typeof define === 'function' && define.amd ? define(factory) : | |
(global.$watch = factory()); | |
}(this, (function () { | |
return $watch; | |
function $watch (handler, object, name) { | |
var handler = typeof handler == "function" ? handler : function(){}, | |
object = object && typeof object == "object" ? object : {} | |
; | |
if (name && typeof name == "string" && typeof object[name] == "undefined") object[name] = undefined; | |
constructor(object, handler, undefined, name); | |
function constructor (object, handler, root, key) { | |
if (key && typeof key == "string") define(object, key, handler, root); | |
else Object.keys(object).forEach(function (key) { | |
define(object, key, handler, root); | |
}); | |
} | |
function clone (o) { | |
if (o === null || typeof o !== "object") return o; | |
if (o instanceof Date) { | |
var c = new Date; | |
c.setTime(o.getTime()); | |
} | |
else { | |
var c = o.constructor(); | |
for (var i in o) c[i] = clone(o[i]); | |
} | |
return c; | |
} | |
function intercept (object, key, handler, root, before, after) { | |
if (before != null && typeof before == "object") { | |
for (var i in before) { | |
if (before.hasOwnProperty(i)) { | |
if (before[i] !== after[i] && typeof after[i] == "undefined") { | |
handler("delete", (root ? root + "." : "") + i, after[i], before[i]); | |
} | |
} | |
} | |
} | |
else if (before !== after && typeof after == "undefined") { | |
handler("delete", root, after, before); | |
} | |
if (after != null && typeof after == "object") { | |
for (var i in after) { | |
if (after.hasOwnProperty(i)) { | |
if (before[i] !== after[i] && typeof before[i] == "undefined") { | |
handler("add", (root ? root + "." : "") + i, after[i], before[i]); | |
define(object, i, handler, root); | |
} | |
} | |
} | |
} | |
else if (before !== after && typeof before == "undefined") { | |
handler("add", root, after, before); | |
debugger; //TODO: What is "i" and "root" in this case? | |
define(object, i, handler, root); | |
} | |
} | |
function define (object, key, handler, root) { | |
if (object.hasOwnProperty(key)) { | |
var value = object[key], $root = (root ? root + "." : "") + key; | |
function $value () { | |
var before = clone(value); | |
setTimeout(function () { | |
intercept(value, key, handler, $root, before, clone(value)); | |
}, 0); | |
return value; | |
} | |
Object.defineProperty(object, key, { | |
enumerable: true, | |
get: function () { | |
return $value(); | |
}, | |
set: function (v){ | |
var old = value; | |
value = v; | |
if (value && typeof value == "object") constructor(value, handler, $root); | |
handler("update", $root, value, old); | |
} | |
}); | |
if (value && typeof value == "object") constructor(value, handler, $root); | |
} | |
} | |
return object; | |
} | |
}))); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Usage example