JS观察者模式

来源:互联网 发布:linux sys.h 编辑:程序博客网 时间:2024/05/22 00:29
使用场景:
1、需要自定义事件的时候可以使用模式
2、当回调嵌套特别复杂时,可以考虑使用该模式
3、当某一操作触发,同时会改变其它模块(比如IM消息到达),可以使用该模式
优点:
代码解耦,模块独立
缺点:
过度使用的话,会导致模块间关系混乱,代码不好维护
var Event = (function() {    var _event,        _default = 'default';    _event = function() {        var _listen,            _trigger,            _remove,            _shift = Array.prototype.shift,            _unshift = Array.prototype.unshift,            namespaceCache = {},            _create,            each = function( ary, fn) {  //循环                var ret;                for(var i = 0, l = ary.length; i < l; i++) {                    var n = ary[i];                    ret = fn.call(n, i, n);                }                return ret;            };        // 订阅        _listen = function(key, fn, cache) {            if(!cache[key]) {                cache[key] = [];            }            cache[key].push(fn);        };        // 移除订阅        _remove = function(key, cache, fn) {            if(cache[key]) {                if(fn) {                    for(var i = cache[key].length; i >=0; i++) {                        if(cache[key][i] === fn) {                            cache[key].splice(i, 1);                        }                    }                }else {                    cache[key] = [];                }            }        };        // 发布        _trigger = function() {            var cache = _shift.call(arguments),                key = _shift.call(arguments),                args = arguments,                _self = this,                stack = cache[key];            if(!stack || !stack.length) {                return;            }            return each(stack, function() {                return this.apply(_self, args);            });        };        // 创建命名空间(同一事件名可能不同处理,比如同时多个IM)        _create = function(namespace) {            var namespace = namespace || _default;            var cache = {},                offlineStack = [],  // 离线事件                ret = {                    listen: function (key, fn, last) {                        _listen(key, fn, cache);                        if (offlineStack == null) {                            return;                        }                        if (last === 'last') {                            offlineStack.length && offlineStack.pop()();                        } else {                            each(offlineStack, function () {                                this();                            });                        }                        offlineStack = null;                    },                    one: function (key, fn, last) {                        _remove(key, cache);                        this.listen(key, fn, last);                    },                    remove: function(key, fn) {                        _remove(key, cache, fn);                    },                    trigger: function() {                        var fn,                            args,                            _self = this;                        _unshift.call(arguments, cache);                        args = arguments;                        fn = function() {                            return _trigger.apply(_self, args);                        };                        if(offlineStack) {                            return offlineStack.push(fn);                        }                        return fn();                    }                };            return namespace ? (namespaceCache[namespace] ? namespaceCache[namespace] : namespaceCache[namespace] = ret) : ret;        };        return {            create: _create,            one: function(key, fn, last) {                var event = this.create();                event.one(key, fn, last);            },            remove: function(key, fn) {                var event = this.create();                event.remove(key, fn);            },            listen: function(key, fn, last) {                var event = this.create();                event.listen(key, fn, last);            },            trigger: function() {                var event = this.create();                event.trigger.apply(this, arguments);            }        };    }();    return _event;})();