js观察者模式与Model
目的
观察者模式是常见的设计模式,可以被应用到MV*框架的Model上,来实现对数据变化的监听。
基本概念
观察者模式是一种常见的设计模式。被观察者可以被订阅(subscribe),并在状态发生改变时通知订阅者。
观察者模式的实现主要涉及三个接口:
1. subscribe (evtName, handler):订阅被观察者的指定事件。
2. unsubscribe (evtName, handler):取消对被观察者指定事件的订阅。
3. publish (evtName, data):被观察者发布指定事件。
这些接口也常被命名为on,off,once,trigger。
代码实现
代码很简单易懂,就不多做解释了:
function Observer() {
this.fns = {};
}
Observer.prototype = {
subscribe: function (evtName, handler) {
if (!this.fns[evtName]) {
this.fns[evtName] = [];
}
this.fns[evtName].push(handler);
},
unsubscribe: function (evtName, handler) {
var arr = this.fns[evtName];
if (!arr) { return; }
var index = arr.indexOf(handler);
if (index !== -1) {
arr.splice(index, 1);
}
},
publish: function (evtName, data) {
var arr = this.fns[evtName];
if (!arr) { return; }
arr.forEach(
function (handler) {
handler(data);
}
);
}
};
使用起来是这样的:
var benben = new Observer();
benben.subscribe('evtA', function (data) { console.log(data); });
benben.publish('evtA', {name: '笨笨'});
与Model结合
接下来我们就要让Model变为可观察的(Observable):
function Model () {
Observer.call(this); // => this.fns = {};
this._data = {}; // 我们将实际数据存放在这里
}
$.merge(Model.prototype, Observer.prototype); // 将方法扩展到Model的prototype上
var model = new Model();
现在我们要做的就是,监听model数据的变化,并发布(publish)。方式包括(并不限于):
1. get与set函数:
Model.prototype.set = function (key, value) {
var oldValue = this._data[key];
this._data[key] = value;
this.publish('change:' + key, {
key: key,
value: value,
oldValue: oldValue
});
}
Model.prototype.get = function (key) {
return this._data[key];
}
model.set('name', '笨笨');
2. setter与getter:
Model.prototype.defineKeys = function (definitions) {
var that = this,
data = this._data;
for (key in definitions) {
this[key] = definitions[key];
this.__defineGetter__(key, function () {
return data[key];
});
this.__defineSetter__(key, function (value) {
var oldValue = data[key];
data[key] = value;
that.publish('change:' + key, {
key: key,
value: value,
oldValue: oldValue
});
});
}
}
/* 或者使用defineProperty
Object.defineProperty(this, key, {
get: function() {
//
},
set: function(value) {
//
}
});
*/
// 需要先define后赋值
model.defineKeys({name: undefined});
model.name = '笨笨';
这两种方式都可以将对model的赋值与事件发布绑定到一起。当然它们各自有各自的缺陷:后者的赋值方式更“自然”,但需要先对字段定义。其他的方式还包括数据脏检测(dirty checking)等,但目的是统一的:将model的变化发布给订阅者,比如通知View来更新等等。
小结
通过使用观察者模式,我们就能监听Model的数据变化(也可以reject不符合条件的赋值等等),并作出相应的动作,比如更新View等等。
扩展:ES6(7)中的Object.observe
Object.observe是未来ES标准之一,包括Chrome 36(beta)+的浏览器已经支持之一特性,不过何时标准最终定稿和普遍实现还是未知。
让我们来了解一下Object.observe:
var obj = {name: 'benben'},
arr = [],
onChange = function (changes) {
changes.forEach(function (change) {
console.log(
change.type, // add, delete, update
change.object,
change.name,
change.oldValue
);
});
};
Object.observe(obj, onChange);
Object.observe(arr, onChange);
obj.name = '笨笨';
arr.push(1);
试试看,第一个情况我们被通知name的变化,第二种情况则被通知[0]和length发生了变化,是不是很方便呢。
我们还可以指定我们感兴趣的字段,以及取消监听:
Object.observe(obj, onChange, ['name', 'gender']); Object.unobserve(obj, onChange);
同时还提供了 Object.getNotifier和notifier.notify两个API来帮助我们发布事件:
function Square () {
this.edge = 0;
}
Square.prototype.setEdge = function (val) {
var notifier = Object.getNotifier(this);
this.edge = val;
notifier.notify({
object: this,
type: 'update',
area: val * val
});
}
var s = new Square(),
onChange = function (changes) {
console.log('onChange...');
changes.forEach(function (change) {
console.log(change);
});
};
Object.observe(s, onChange);
s.setEdge(5);
注意s并没有area字段,我们通过notifier的notify方法来发布变化事件。
如果被观察者认为观察者并不应该关注某些字段的变化(不同于观察者只选择观察指定字段集),这是我们可以使用notifier的performChange方法:
Square.prototype.setEdge = function (val) {
var notifier = Object.getNotifier(this);
notifier.performChange('area', function() {
this.edge = val;
}, this);
notifier.notify({
object: this,
type: 'update',
area: val * val
});
}
我们在performChange的回调中设置了edge的值,这种情况下,edge的变化并不会被发布。
js观察者模式与Model的更多相关文章
- Backbone.js 中的Model被Destroy后,不能触发success的一个原因
下面这段代码中, 当调用destroy时,backbone会通过model中的url,向服务端发起一个HTTP DELETE请求, 以删除后台数据库中的user数据. 成功后,会回调触发绑定到dest ...
- Node.js与Sails~Model和ORM的持久化
回到目录 上一讲说了在sails里定义model及相关参数的说明,这一讲主要说一下如何将你的Model持久化到文件,关系数据库和Nosql数据库里,在持久化这点上,sails是统一管理的,它可以在/c ...
- Backbone.js学习之Model
首先,我们看一下官方文档中对Model的解释(或者说定义): Models are the heart of any JavaScript application, containing the in ...
- Backbone.js 中使用 Model
前面几篇 Backbone.js 的例子中有使用到 template, 及数据的填充,其实这已经很接近 Model 了.现在来学习怎么创建自己的 Model 类,并简单的使用.Backbone.js ...
- [Node.js] Create a model to persist data in a Node.js LoopBack API
In this lesson you will learn what a LoopBack model is, you will create a Product model using the Lo ...
- js - 观察者模式与订阅发布模式
零.序言 转载&参考: 1.JavaScript 设计模式系列 - 观察者模式 2.JavaScript 设计模式(六):观察者模式与发布订阅模式 一.观察者模式(observer) 概要: ...
- Node.js与Sails~Model数据模型
回到目录 对于Sails来说,它的Model与数据库对应,不过它并没有采用目前比较流行的poco贫血模型,而是采用了类似DDD的充血模型,即它的数据实体里即有数据库字段(属性)而且还有方法,而模型里的 ...
- js观察者模式
观察者模式存在观察者和被观察者 被观察者的状态发生改变,通知观察者调用观察者的update方法,观察者的update方法对被观察者的状态进行检测,做出相应的操作 被观察者存在接口attach,deta ...
- 浅谈js观察者模式
观察者模式又叫发布订阅模式,它可以让多个观察者对象同时监听某一个主题对象,即在一个事件发生时,不同的对象迅速对其进行相应.就比如当又人闯红灯,不同的人对这件事迅速发起响应,当然这个比喻不太恰当,不过在 ...
随机推荐
- (转)Vim的Python编辑器详细配置过程 (Based on Ubuntu 12.04 LTS)
为什么要用vim编辑py文件? 因为在Linux命令行中,缺少图形界面的IDE,vim是最佳的文本编辑器,而为了更好的编辑py文本,所以配置vim. 1. 安装完整版vim vi和vim的区别? 在L ...
- 简单三段式状态机实验1-SOS
一直想从一段式状态机切换到三段式状态机,从书上和网上不断搜寻三段式案例及方法,感觉很简单,就想拿之前做过的实验把一段式改成三段式,可是写起来并非那么简单,很棘手,改完后也没有成功,尤其状态机里面的计数 ...
- js中原生对象、内置对象和宿主对象(转)
本帖最后由 无解. 于 2012-9-9 12:13 编辑 <ignore_js_op> 这个图来自于<JavaScript语言精髓与编程实践>第三章P184页.最近在改第二版 ...
- sql语句之字符串匹配like
sql没有正则表达式,只能使用like 语法 match_expression [ NOT ] LIKE pattern [ ESCAPE escape_character ] 参数 match_ex ...
- Java设计模式--Java Builder模式
1.Java Builder模式主要是用一个内部类去实例化一个对象,避免一个类出现过多构造函数,而且构造函数如果出现默认参数的话,很容易出错. public Person(String name) P ...
- Android音频系统之AudioFlinger(一)
1.1 AudioFlinger 在上面的框架图中,我们可以看到AudioFlinger(下面简称AF)是整个音频系统的核心与难点.作为Android系统中的音频中枢,它同时也是一个系统服务,启到承上 ...
- k-means算法的Python实现
#coding=utf-8 import codecs import numpy from numpy import * import pylab def loadDataSet(fileName): ...
- [iOS]C语言技术视频-08-结构体的定义
下载地址: 链接: http://pan.baidu.com/s/1dlEFW 密码: 9e5u
- C# 开发系列(二)
1. 参考文档:http://www.yiibai.com/csharp/csharp_environment_setup.html 2. C# ,ASP.NET HTTP Authorization ...
- SQL Server--导入和导出向导
作用:创建一个只需要最少的转换就可以快速导入或导出数据的包 操作步骤: 1 打开打入和导出向导方式 有四种方式 1)在SSMS(SQL Server Management Studio)中,右击目标数 ...