1

持久化记录

需要一种保持记录持久化的方法,即将引用保存至新创建的实例中以便任何时候都
能访问它。通过在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富应用开发》为主要学习资料。】


JingDing
2.5k 声望124 粉丝

新手请多多指教~