封裝 :Javascript中創(chuàng)建對象的模式中,個(gè)人認(rèn)為通過閉包才算的上是真正意義上的封裝 ,所以首先我們先來簡單介紹一下閉包,看下面這個(gè)例子:
復(fù)制代碼 代碼如下:
<script type="text/Javascript">
function myInfo(){
var name ="老魚",age =27;
var myInfo = "my name is" + name + "i am" + age +"years old";
function showInfo(){
alert(myInfo);
}
return showInfo;
}
var oldFish = myInfo();
oldFish();
</script>
是不是很眼熟呢?沒錯(cuò)了,這其實(shí)就是一個(gè)簡單的閉包應(yīng)用了。簡單解釋一下:上面的函數(shù)myInfo中定義的變量,在它的內(nèi)嵌函數(shù)showInfo中是可訪問的(這個(gè)很好理解),但是當(dāng)我們把這個(gè)內(nèi)嵌函數(shù)的返回引用賦值給一個(gè)變量oldFish,這個(gè)時(shí)候函數(shù)showInfo是在myInfo函數(shù)體外被調(diào)用,但是同樣可以訪問到定義在函數(shù)體內(nèi)的變量。oh yeah!
總結(jié)一下閉包的原理吧:函數(shù)是運(yùn)行在定義他們的作用域中而不是調(diào)用他們的作用域中。 其實(shí)返回一個(gè)內(nèi)嵌函數(shù)也是創(chuàng)建閉包最常用的一種方法!
如果覺得上面的解釋太抽象的話,那么我們一起重塑上面的函數(shù),看看這樣是否層次鮮明一些:
復(fù)制代碼 代碼如下:
<script type="text/Javascript">
var ioldFish = function(name,age){
var name = name,age = age;
var myInfo = "my name is" + name + "i am" + age +"years old";
return{
showInfo:function(){
alert(myInfo);
}
}
}
ioldFish("老魚",27).showInfo();
</script>
上例中的編碼風(fēng)格是ext yui 中比較常見的,公私分明,一目了然。通過閉包,我們可以很方便的把一些不希望被外部直接訪問到的東西隱藏起來,你要訪問函數(shù)內(nèi)定義的變量,只能通過特定的方法才可以訪問的到,直接從外部訪問是訪問不到的,寫的挺累,饒了一圈終于轉(zhuǎn)回來了,封裝嘛,不就是把不希望被別人看到的東西隱藏起來嘛!哈哈……
上例如果轉(zhuǎn)換成JQ 的風(fēng)格的話,應(yīng)該如下例所寫,這樣的封裝模式屬于門戶大開型模式,里面定義的變量是可以被外部訪問到的(下面的例子如果你先實(shí)例化一個(gè)對象,然后在函數(shù)外部訪問對象的name或者 age屬性都是可以讀取到的)當(dāng)然這種模式下我們可以設(shè)置一些”潛規(guī)則”,讓團(tuán)隊(duì)開發(fā)成員明白哪些變量是私用的,通常我們?nèi)藶榈脑谒接凶兞亢头椒ㄇ凹酉聞澗€”_”,標(biāo)識警戒訊號!從而實(shí)現(xiàn)”封裝”!
復(fù)制代碼 代碼如下:
<script type="text/Javascript">
var ioldFish = function(name,age){
return ioldFish.func.init(name,age);
};
ioldFish.func = ioldFish.prototype ={
init:function(name,age){
this.name = name;
this.age = age;
return this;
},
showInfo:function(){
var info = "my name is" + this.name +"i am " +this.age+"years old";
alert(info);
}
};
ioldFish.func.init.prototype = ioldFish.func;
ioldFish(" 老 魚",27).showInfo();
//var oldFish = new ioldFish("老魚",27);
//alert(oldFish.name);
</script>
可能有人會問,哪種模式好呢?這個(gè)怎么說呢?兩種方式都有優(yōu)缺點(diǎn),結(jié)合著用唄!總之一個(gè)原則,一定一定不能直接被外部對象訪問的東西,就用閉包封裝吧。”一定一定”四個(gè)字很深?yuàn)W,不斷實(shí)踐中才能體會真諦!
繼承 :提到這個(gè)的時(shí)候,要順便再補(bǔ)充一句:閉包封裝中的一個(gè)缺點(diǎn),不利于子類的派生,所以閉包有風(fēng)險(xiǎn),封裝需謹(jǐn)慎!直觀起見,下面例子中創(chuàng)建對象的方式,采用”門戶大開型”模式。
在Javascript中繼承 一般分為三種方式:”類式繼承”,”原型繼承”,”摻元類”。下面簡單的介紹一下三類繼承方式的原理。
A.類式繼承: 這個(gè)是現(xiàn)在主流框架中常用的繼承方式,看下例:
復(fù)制代碼 代碼如下:
<script type="text/Javascript">
var Name = function(name){
this.name = name;
};
Name.prototype.getName = function(){
alert(this.name);
};
var Fish = function(name,age){
Name.call(this,name);
this.age = age;
};
Fish.prototype = new Name();
Fish.prototype.constructor = Fish;
Fish.prototype.showInfo = function(){
alert(this.age);
}
var ioldFish = new Fish("老魚",27);
ioldFish.getName();
</script>
上述子類Fish中并沒定義getName方法,但是子類Fish的實(shí)例對象ioldFish依然調(diào)用到了該方法,這是因?yàn)樽宇怓ish繼承了超類 Name中定義的getName方法。解釋一下,這里子類Fish的prototype指到了超類的一個(gè)實(shí)例,在子類Fish中雖然沒有申明 getName方法,但是根據(jù)原型鏈原理,會向prototype指向的上一級對象中去查找是否有該方法,如果沒找到該方法,會一直搜索到最初的原型對象。這其實(shí)也就是繼承的原理了。這里特別說明一下,F(xiàn)ish.prototype.constructor = Fish;這句,由于默認(rèn)子類的prototype應(yīng)該是指向本身的,但是之前把prototype指向到了超類的實(shí)例對象,所以在這里要把它設(shè)置回來。當(dāng)然這里可以把相關(guān)代碼通過一個(gè)函數(shù)來組織起來,起到偽裝extend的作用
B.原型繼承 ,從內(nèi)存性能上看優(yōu)于類式繼承。
復(fù)制代碼 代碼如下:
<script type="text/Javascript">
function clone(object){
var F = function(){};
F.prototype = object;
return new F();
};
var Name = {
name:"who's name",
showInfo:function(){
alert(this.name);
}
};
var Fish = clone(Name);
//Fish.name = "老魚";
Fish.showInfo();
lt;/script>
很明顯,原型繼承核心就是這個(gè)clone函數(shù),同樣是原型鏈的原理,不同的是它直接克隆超類,這樣的話子類就繼承了超類的所有屬性和方法.特別說一下,這類繼承并不需要?jiǎng)?chuàng)建構(gòu)造函數(shù),只需要?jiǎng)?chuàng)建一個(gè)對象字變量,定義相應(yīng)的屬性和方法,然后在子類中只需要通過圓點(diǎn)”.”符號來引用屬性和方法就可以了.
JavaScript技術(shù):JavaScript 面向?qū)ο笕腴T精簡篇第1/2頁,轉(zhuǎn)載需保留來源!
鄭重聲明:本文版權(quán)歸原作者所有,轉(zhuǎn)載文章僅為傳播更多信息之目的,如作者信息標(biāo)記有誤,請第一時(shí)間聯(lián)系我們修改或刪除,多謝。