原文:http://www.verydemo.com/demo_c98_i17045.html
这次要和大家深入说的是MODEL,个人认为也是比较难于理解的一个概念,所以希望可以和大家一同去探讨。
引入MVC模式中,我们把数据的管理归类进了模型,即我们应该把数据操作和行为相关的逻辑都放进模型中。
在实际的操作中我们最好通过命名空间的方法来进行管理,如下:
var User={ record:[] }
那么我们User的记录就可以存放在User.record中了,如果你想为User增加一些CRUD的方法也可以,如下:
var User={ record:[], update:function(){}, delete:function(){} }
好的,你可以看到我们通过命名空间的方法可以很优雅地(OK,我有时候感觉用“优雅”这个词特别装逼,就像一些翻译工具译过来,但是用着用着就觉得这个词语形容得特别有程序猿的范儿,见笑)把一些方法集成到User中。当然有时候我们想删除某个user是想以以下这种方式操作:
user.delete() //通过类似的绑定实例删除
而并非:
User.delete(id) //你需要传入一个ID来标示删除的到底是哪个用户
所以这个时候,你就应该意识到我们应该把User构建成一个类,并且通过构建user实例进行实例的操作,如下:
var User=function(){ this.record=[]; } User.prototype.delete=function(){ /*具体的删除实例操作*/ } var user=new User;
接下来我们需要利用Object.create()的来构建我们的ORM(根据《软件程序设计与艺术》一书的“无绪”一词,不需要过分了解细节的含义,我们只需要知道ORM就是包装了一些数据的对象,其中它是抽象的,类似接口的概念,你们意会一下吧,作为一名程序猿需要有丰富的想象力!!!),其中Object.create()的作用非常简单,它只有一个参数,并且返回一个新的对象,而新对象的原型就是参数对象,好吧,如果你的浏览器不支持这个方法我们也可以自行添加,同时也可以帮助大家理解这个方法的工作原理,非常简单:
....................................................................
if (typeof Object.create !== 'function') { Object.create = function (o) { function F() {} F.prototype = o; return new F(); }; } newObject = Object.create(oldObject);//注意这里传入的是一个对象,并非函数
可以说整个继承是基于原型的(当然,我刚刚发现了一种JS面向对象的另外一种模仿方法,并且摒弃了原型,this等等的复杂概念,推荐http://www.cnblogs.com/cloudlee/archive/2012/07/15/2592849.html),接下来我们要来利用Object.create()来创建Model对象:
var Model={ inherited:function(){}, created:function(){}, prototype:{ init:function(){ } }, create:function(){//创建具体的模型 var object=Object.create(this);//创建新模型对象,继承ORM的所有方法 object.parent=this;//this这时指向的是ORM,以ORM作为新模型的父类 object.prototype=Object.create(this.prototype);//新模型原型继承ORM prototype里面的方法init,即让新模型的实例拥有这个init方法 object.created(); return object;//返回新模型 }, init:function(){ var instance=Object.create(this.prototype);//创建新实例,注意该实例是有新模型创建的,所以这里的this是指新模型,实例继承新模型的prototype方法,即init() instance.parent=this;//实例父类指向为新模型,这个很容易理解 instance.init.apply(instance,arguments);//实例调用所继承的init() return instance;//返回实例 } } var User=Model.create() var user=User.init()
事实上,我认为这段代码还是比较难理解的,它需要你比较了解整个原型链的机制,所以我特地都标上了注释,希望大家能看懂。事实上在我看的书上有关于增加这个ORM的一些方法和属性的操作,但是由于我们构建这个ORM的目的就是为了抽象需求,所以我们利用一些方法来扩展它而不采用硬编码进ORM体内。
include:function(obj){//由Model调用,把方法属性添加进ORM中,让新模型的原型继承,即让新模型的实例继承 $.extend(this.prototype,obj) }, extend:function(obj){//由Model调用,把方法属性添加进ORM中,让新模型继承 $.extend(this,obj) }
看到这,大家应该知道我采用了jQuery,为了减轻我们的工作量,之后的一些代码我们都会利用到jQuery(我相信你不会介意的),然后我们把这个方法写进去以后可以直接通过Model调用:
Model.include({ init:function(attributes){//重写新模型实例的初始方法,传入参数后调用新加入方法load() if(attributes)this.load(attributes); }, load:function(attributes){//该方法把所传入对象的属性方法加入到实例中 jQuery.extend(this,attributes); } })
接下来我们要做的就是对实例的一个持久化,就说是你创建了一个实例需要保存它的信息,不仅仅是每个实例的详细信息,还要知道我们整个新模型里到底有多少个实例等,于是乎我们加入以下的一些方法来完成这个工作:
Model.include({ newRecord:true, init:function(attributes){ if(attributes)this.load(attributes); }, load:function(attributes){ jQuery.extend(this,attributes); }, create:function(){ this.newRecord=false; this.parent.records[this.id]=this; }, destory:function(){ delete this.parent.records[this.id]; }, update:function(){ this.parent.records[this.id]=this; }, save:function(){ this.newRecord?this.create():this.update(); },
}) Model.extend({ created:function(){ this.records={} //重写created(),为新模型创建一个records对象记录实例 }, find:function(id){ return this.records[id]||"找不到相应的记录"; } }) var User=Model.create(); var user=User.init(); var User2=Model.create(); var user2=User2.init(); user.name="chiu"; user.id=1; user.save(); user2.name="chiu2"; user2.id=2; user2.save(); //以下说明两个模型的记录是分离的 console.log(User.records); console.log(User2.records);
通过这种方法就可以把我们新建的实例进行一系列的操作,同时父类模型也会对它们进行记录。现在我们再来观察下整个程序的一个问题:
console.log(User.find(1).name);//输出chiu User.find(1).name="john"; console.log(User.find(1).name);//输出john
我们不应该能修改查找的数据从而修改实例的属性,所以我们应该把查找的结果作一个备份返回,当然具体的实现这里就不说了,你们应该也会知道如何操作。还有另外一个问题是当创建实例的时候我们都需要手动创建id,这样的方法既麻烦,又容易出错(需要保持没有重复的id值),因此我们可以通过CUID的方法来生成一个唯一的id:
网上有很多这类的代码可以直接套过来,以下是其中一种
guid:function(){ function G() {return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1)} return (guid = (G() + G() + "-" + G() + "-" + G() + "-" + G() + "-" + G() + G() + G()).toUpperCase()); }
生成guid的代码你可以随便放哪里都可以,我个人是让新模型给继承了,然后我们再重写一下实例create()的方法
create:function(){ this.newRecord=false; if(!this.id)this.id=this.parent.guid(); this.parent.records[this.id]=this; }
那么现在我构建一个简单的模型基本上是完成了,(好辛苦啊,写了这么多)。下一节是讲述如何在模型中引入数据的装载和提交。