這次要和大家深入說的是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()的作用非常簡單,它只有一個參數,並且返回一個新的對象,而新對象的原型就是參數對象,好吧,如果你的瀏覽器不支持這個方法我們也可以自行添加,同時也可以幫助大家理解這個方法的工作原理,非常簡單:
引用自:http://javascript.crockford.com/prototypal.html
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; }
那么現在我構建一個簡單的模型基本上是完成了,(好辛苦啊,寫了這么多)。下一節是講述如何在模型中引入數據的裝載和提交。