AngularJS Scope Digest recreation (extended)

for http://stepansuvorov.com/blog/

by Stepan Suvorov

JavaScript

//(function () {
var rootScope = function () {
    this.watchers = [];
};
rootScope.prototype = {
    watch: function (watchExp, listener) {
        var watcher = {
            watchExp: watchExp,
            listener: listener,
            lastValue: this[watchExp],
        }, scope = this;
        this.watchers.push(watcher);
        return function unwatch(){
            scope.watchers.splice(scope.watchers.indexOf(watcher), 1);
        };
    },
    digest: function () {
        var dirty,
            ttl = 10;
        do {
            dirty = digestOnce(this);
            if (dirty && !(ttl--)) {
               throw "10 digest iterations reached";
            }
        } while (dirty);

        function digestOnce(scope) {
            var dirty = false;
            scope.watchers.forEach(function (watcher) {
                if (watcher.lastValue !== scope[watcher.watchExp]) {
                    watcher.listener.call(scope, scope[watcher.watchExp], watcher.lastValue);
                    watcher.lastValue = scope[watcher.watchExp];
                    dirty = true;
                }
            });
            return dirty;
        }
    }
}

//    window.rootScope = rootScope;
//})();


var scope = new rootScope();
scope.x = 5;
var unwatch = scope.watch('x', function (newValue, oldValue) {
    alert('changed:' + oldValue + '->' + newValue)
});
scope.x = 10;
scope.digest();
unwatch();
scope.x = 15;
scope.digest();