1. 정의
관찰자 패턴(publish-subscribe 패턴): 객체 간의 일대다 종속 관계를 정의합니다. 객체의 상태가 변경되면 이에 의존하는 모든 객체에 알림이 전송됩니다.
JavaScript에서 이벤트 모델은 일반적으로 전통적인 관찰자 패턴을 대체하는 데 사용됩니다.
혜택:
2. DOM 이벤트 – 관찰자 모드의 전형적인 예
document.body에서 사용자의 클릭 동작을 모니터링해야 하지만 사용자가 언제 클릭할지 예측할 방법이 없습니다.
따라서 document.body에서 click 이벤트를 구독합니다. body 노드를 클릭하면 body 노드가 구독자에게 이 메시지를 게시합니다.
document.body.addEventListener("click", function() { console.log(1); }, false); // 可以多个订阅者 document.body.addEventListener("click", function() { console.log(2); }, false); doucment.body.click();
특정 웹사이트에는 헤더, 탐색 탐색, 메시지 목록 및 기타 모듈이 있습니다. 이러한 모듈을 렌더링하려면 사용자 로그인 정보를 얻어야 합니다.
(1) 일반 글쓰기 :
$.ajax({ url: './login', type: 'post', contentType: 'application/json', dataType:'json', success: function(data) { if(data.status === "success") { // 登录成功,渲染header、nav header.setInfo(data.headerInfo); nav.setInfo(data.navInfo); } } });
(2) 관찰자 패턴을 사용하면 분리가 쉽습니다!
$.ajax({ ..., success: function(data) { if(data.status === "success") { // 登录成功,发布登陆成功消息 login.trigger("loginsuccess", data); } } }); var header = (function() { // 监听消息 login.listen("loginsuccess", function(data){ header.setInfo(data.headerInfo); }); return { setInfo: function(data) { console.log("设置header信息"); } }; })(); var nav = (function() { login.listen("loginsuccess", function(data){ nav.setInfo(data.navInfo); }); return { setInfo: function(data) { console.log("设置nav信息"); } } })();
3. 범용 관찰자 모드
/* * 示例: * Event.create("namespace1").listen('click', function(a){ * console.log(a); * }); * Event.create("namespace1").trigger("click", 1); */ var Event = (function() { var global = this, Event, _default = 'default'; Event = function() { var _listen, _trigger, _remove, _slice = Array.prototype.slice, _shift = Array.prototype.shift, _unshift = Array.prototype.unshift, namespaceCache = [], _create, find, 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, ret, stack = cache[key]; if(!stack || !stack.length) { return; } return each(stack, function() { return this.apply(_self, args); }); }; // 创建命名空间 _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, last) { _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; })();
이 기사가 자바스크립트 프로그래밍을 배우는 모든 사람에게 도움이 되기를 바랍니다.