{"id":203,"date":"2015-04-10T20:11:39","date_gmt":"2015-04-10T20:11:39","guid":{"rendered":"https:\/\/www.tech.shinynewthings.com\/?p=203"},"modified":"2015-04-12T22:40:55","modified_gmt":"2015-04-12T22:40:55","slug":"observer-implementation-using-defineproperties","status":"publish","type":"post","link":"https:\/\/www.tech.shinynewthings.com\/?p=203","title":{"rendered":"Observer Implementation &#8211; using defineProperties"},"content":{"rendered":"<p>Testing Object.defineProperties using the Observer pattern. MDN shows that defaults for configurable, enumerable and writable are false. The implementation below is explicitly setting those values to false as a reminder.<\/p>\n<pre>function MakeObservable(obj) {\n\n    obj = obj || this;\n\n    \/\/obj._observers = [];\n\n    Object.defineProperties (obj, {\n\n        _observers: {\n            value: [],\n            configurable: false,\n            enumerable: false,\n            writable : false\n        },\n\n        _watch: {\n            value: function (name, observer, func) {\n                if (!obj._observers.hasOwnProperty(name)) {\n                    obj._observers[name] = ({observer:observer, func:func});\n                } else {\n                    console.log('This property already exists on this object');\n                }\n\n            },\n            configurable: false,\n            writable : false\n        },\n        \n        _unwatch: {\n            value: function (observer) {\n                var idx = obj._observers.indexOf(observer);\n                if (idx > -1) {\n                    obj.slice(idx, 1);\n                }\n            },\n            configurable: false,\n            writable : false\n        },\n\n        _updateWatcher: {\n            value: function (observer) {\n                console.log(\"Generic Notification from Watched Object\\n - Cannot Customize\");\n            },\n            configurable: false, \n            writable : false\n        },\n        \n        _updateWatchers: {\n            value: function (prop, value) {\n                var len = obj._observers.length;\n                for (var prop in obj._observers) {\n                    \/\/ INTERNAL OBJECT NOTIFICATION\n                    \/\/obj._updateWatcher(obj._observers[watcher]);\n                    \/\/ GET WATCHER\n                    var watcher = obj._observers[prop];\n                    \/\/ CALL WATCHERS CUSTOM METHOD\n                    watcher.func(prop, value);\n                };\n            },\n        },\n        set: {\n            value: function(prop, value) {\n                obj[prop] = value;\n                obj._updateWatchers(prop, value);\n            }\n        },\n        get: {\n            value: function(prop) {\n                return obj[prop];\n            }\n        }\n    });\n    \n    obj.set = function(prop, value) {\n        obj[prop] = value;\n        obj._updateWatchers(prop);\n\n    };\n\n    obj.get = function(prop) {\n        return obj[prop];\n    };\n\n    return obj;\n}\n\nvar obj = new MakeObservable();\n\n\/\/ CREATE WATCHER\nvar watcher = {\n    func: function(prop, value) {\n        console.log(\"FIRST WATCHER\", prop, value);\n    }\n};\n\n\/\/ ADD WATCHER NAME, WATCHER AND FUNCTION TO BE CALLED ON UPDATE\nobj._watch(\"watcher\", watcher, watcher.func);\n\n\/\/ TEST WATCHERS\nobj.set('name', 'First Name');\n\n\/\/ CREATE WATCHER\nvar watcher2 = { \n    func: function(prop, value) { \n        console.log(\"SECOND WATCHER\", prop, value); \n    }\n};\n\n\/\/ ADD SECOND WATCHER NAME, WATCHER AND FUNCTION TO BE CALLED ON UPDATE\nobj._watch(\"watcher2\", watcher2, watcher2.func);\n\n\/\/ TEST WATCHERS\nobj.set('name', 'Second Name');\n<\/pre>\n","protected":false},"excerpt":{"rendered":"<p>Testing Object.defineProperties using the Observer pattern. MDN shows that defaults for configurable, enumerable and writable are false. The implementation below is explicitly setting those values to false as a reminder. function MakeObservable(obj) { obj = obj || this; \/\/obj._observers = []; Object.defineProperties (obj, { _observers: { value: [], configurable: false, enumerable: false, writable : false [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"class_list":["post-203","post","type-post","status-publish","format-standard","hentry","category-uncategorized"],"_links":{"self":[{"href":"https:\/\/www.tech.shinynewthings.com\/index.php?rest_route=\/wp\/v2\/posts\/203","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.tech.shinynewthings.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.tech.shinynewthings.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.tech.shinynewthings.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.tech.shinynewthings.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=203"}],"version-history":[{"count":4,"href":"https:\/\/www.tech.shinynewthings.com\/index.php?rest_route=\/wp\/v2\/posts\/203\/revisions"}],"predecessor-version":[{"id":207,"href":"https:\/\/www.tech.shinynewthings.com\/index.php?rest_route=\/wp\/v2\/posts\/203\/revisions\/207"}],"wp:attachment":[{"href":"https:\/\/www.tech.shinynewthings.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=203"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.tech.shinynewthings.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=203"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.tech.shinynewthings.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=203"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}