持久化记录
需要一种保持记录持久化的方法,即将引用保存至新创建的实例中以便任何时候都
能访问它。通过在Model 中使用records 对象来实现。当保存一个实例的时候,
就将它添加进这个对象中;当删除实例时,和将它从对象中删除:
// 用来保存资源的对象
Model.records = {};
Model.include({
newRecord: true,
create: function(){
this.newRecord = false;
this.parent.records[this.id] = this;
},
destroy: function(){
delete this.parent.records[this.id];
}
});
更新一个已存在的实例——只需更新对象引用即可:
Model.include({
update: function(){
this.parent.records[this.id] = this;
}
});
现在创建一个快捷函数来保存实例,这样就不用每次都检查这个实例是否已经保存过或
是否需要新创建实例了:
// 将对象存入hash 记录中,保持一个引用指向它
Model.include({
save: function(){
this.newRecord ? this.create() : this.update();
}
});
用来根据ID 查找资源的find() 函数:
Model.extend({
// 通过ID 查找,找不到则抛出异常
find: function(id){
return this.records[id] || throw("Unknown record");
}
});
现在已经成功地创建了一个基本的ORM,运行一下:
var asset = Asset.init();
asset.name = "same, same";
asset.id = 1
asset.save();
var asset2 = Asset.init();
asset2.name = "but different";
asset2.id = 2;
asset2.save();
assertEqual( Asset.find(1).name, "same, same" );
asset2.destroy();
增加 ID 支持
此时每次保存一条记录都必须手动指定一个ID。可以加入自动化处理。首先,我们需要一个方法来自动生成ID,可以使用全局统一标识(Globally UniqueIdentifier,简称GUID)生成器来做这一步。从技术的角度讲,出于API 的原因,JavaScript 无法友好正式地生成128 位的GUID,它只能生成伪随机数。虽然JavaScript 中内置的Math.random() 方法尽管产生的是伪随机数,但也足够用了。
Robert Kieffer 写了一个简单明了的GUID 生成器,它使用Math.random() 来产生一个伪
随机数的GUID(http://goo.gl/0b0hu),代码也很简单:
Math.guid = function(){
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
var r = Math.random()*16|0, v = c == 'x' ? r : (r&0x3|0x8);
return v.toString(16);
}).toUpperCase();
};
现在有了生成GUID 的方法,可以很容易将它集成到ORM 里,剩下的只需修改
create() 函数了:
Model.extend({
create: function(){
if ( !this.id )
this.id = Math.guid();
this.newRecord = false;
this.parent.records[this.id] = this;
}
});
这样任何新创建的记录都包含一个随机的GUID 作为它们的ID :
var asset = Asset.init();
asset.save();
asset.id //=> "54E52592-313E-4F8B-869B-58D61F00DC74"
寻址引用
目前创建的ORM 中存在一个与引用相关的bug。当保存或
通过find() 查找记录时,所返回的实例并没有复制一份,因此对任何属性的修改都会影
响原始资源。改进:
var asset = new Asset({name: "foo"});
asset.save();
// 正确传入资源
assertEqual( Asset.find(asset.id).name, "foo" );
// 更改属性,而没有调用update()
asset.name = "wem";
// 出问题了,因为asset 的名字被修改为“wem”
assertEqual( Asset.find(asset.id).name, "foo" );
需要修复这个问题,在执行find() 操作的时候新创建一个对象,同样在创建或更新
记录的时候需要复制对象:
Asset.extend({
find: function(id){
var record = this.records[id];
if ( !record ) throw("Unknown record");
return record.dup();
}
});
Asset.include({
create: function(){
this.newRecord = false;
this.parent.records[this.id] = this.dup();
},
update: function(){
this.parent.records[this.id] = this.dup();
},
dup: function(){
return jQuery.extend(true, {}, this);
}
});
这里存在另外一个问题,Model.records 是被所有模型所共享的对象:
assertEqual( Asset.records, Person.records );
但这在合并所有的记录时会有副作用:
var asset = Asset.init();
asset.save();
assert( asset in Person.records );
解决办法是在创建新的模型时设置一个新的records 对象。Model.create() 是创建新对
象的回调,因此我们可以设置任意描述这个模型的对象:
Model.extend({
created: function(){
this.records = {};
}
});
【公开记录学习JS MVC,不知道能坚持多久= =。以《基于MVC的JavaScript web富应用开发》为主要学习资料。】