JS中的面向對象編程泥耀?

一神郊、背景介紹

什么是面向對象編程?

Javascript是一種基于對象(object-based)的語言宅静,你遇到的所有東西幾乎都是對象章蚣。

今天主要內(nèi)容是兩個點:封裝和繼承。

二姨夹、知識剖析

如何把“屬性”(PROPERTY)和"方法"(METHOD)纤垂,封裝成一個對象?

1匀伏、 生成實例對象的原始模式

假定我們把貓看成一個對象洒忧,它有"名字"和"顏色"兩個屬性。

var Cat = {

name : '',

color : ''

}

現(xiàn)在够颠,我們需要根據(jù)這個原型對象的規(guī)格(schema)熙侍,生成兩個實例對象。

var cat1 = {}; // 創(chuàng)建一個空對象

cat1.name = "大毛"; // 按照原型對象的屬性賦值

cat1.color = "黃色";

var cat2 = {};

cat2.name = "二毛";

cat2.color = "黑色";

好了履磨,這就是最簡單的封裝了蛉抓,把兩個屬性封裝在一個對象里面。但是剃诅,這樣的寫法有兩個缺點巷送,一是如果多生成幾個實例,寫起來就非常麻煩矛辕;二是實例與原型之間笑跛,看不出有什么聯(lián)系。

2聊品、 原始模式的改進

我們可以寫一個函數(shù)飞蹂,解決代碼重復的問題。

然后生成實例對象翻屈,就等于是在調用函數(shù):

這種方法的問題依然是陈哑,cat1和cat2之間沒有內(nèi)在的聯(lián)系,不能反映出它們是同一個原型對象的實例伸眶。

3惊窖、 構造函數(shù)模式

為了解決從原型對象生成實例的問題,Javascript提供了一個構造函數(shù)(Constructor)模式厘贼。

所謂"構造函數(shù)"界酒,其實就是一個普通函數(shù),但是內(nèi)部使用了this變量嘴秸。對構造函數(shù)使用new運算符毁欣,就能生成實例售担,并且this變量會綁定在實例對象上。

比如署辉,貓的原型對象現(xiàn)在可以這樣寫族铆,

我們現(xiàn)在就可以生成實例對象了。

4哭尝、構造函數(shù)模式的問題

構造函數(shù)方法很好用哥攘,但是存在一個浪費內(nèi)存的問題。

請看材鹦,我們現(xiàn)在為Cat對象添加一個不變的屬性type(種類)逝淹,再添加一個方法eat(吃)。那么桶唐,原型對象Cat就變成了下面這樣:

還是采用同樣的方法栅葡,生成實例

表面上好像沒什么問題,但是實際上這樣做尤泽,有一個很大的弊端欣簇。那就是對于每一個實例對象,type屬性和eat()方法都是一模一樣的內(nèi)容坯约,每一次生成一個實例熊咽,都必須為重復的內(nèi)容,多占用一些內(nèi)存闹丐。這樣既不環(huán)保横殴,也缺乏效率。

5卿拴、 PROTOTYPE模式

Javascript規(guī)定衫仑,每一個構造函數(shù)都有一個prototype屬性,指向另一個對象堕花。這個對象的所有屬性和方法文狱,都會被構造函數(shù)的實例繼承。

這意味著航徙,我們可以把那些不變的屬性和方法如贷,直接定義在prototype對象上陷虎。

然后到踏,生成實例。

這時所有實例的type屬性和eat()方法尚猿,其實都是同一個內(nèi)存地址窝稿,指向prototype對象,因此就提高了運行效率凿掂。

三伴榔、常見問題

如何實現(xiàn)構造函數(shù)的繼承?

四纹蝴、解決方案

比如,現(xiàn)在有一個"動物"對象的構造函數(shù)踪少。

還有一個"貓"對象的構造函數(shù)塘安。

怎樣才能使"貓"繼承"動物"呢?

1援奢、 構造函數(shù)綁定

第一種方法也是最簡單的方法兼犯,使用call或apply方法,將父對象的構造函數(shù)綁定在子對象上集漾,即在子對象構造函數(shù)中加一行:

2切黔、 PROTOTYPE模式

第二種方法更常見,使用prototype屬性具篇。

如果"貓"的prototype對象纬霞,指向一個Animal的實例,那么所有"貓"的實例驱显,就能繼承Animal了诗芜。

代碼的第一行,我們將Cat的prototype對象指向一個Animal的實例埃疫。它相當于完全刪除了prototype 對象原先的值绢陌,然后賦予一個新值。但是熔恢,第二行又是什么意思呢脐湾?任何一個prototype對象都有一個constructor屬性,指向它的構造函數(shù)叙淌。如果沒有"Cat.prototype = new Animal();"這一行秤掌,Cat.prototype.constructor是指向Cat的;加了這一行以后鹰霍,Cat.prototype.constructor指向Animal闻鉴。更重要的是,每一個實例也有一個constructor屬性茂洒,默認調用prototype對象的constructor屬性孟岛。因此,在運行"Cat.prototype = new Animal();"這一行之后督勺,cat1.constructor也指向Animal渠羞!這顯然會導致繼承鏈的紊亂(cat1明明是用構造函數(shù)Cat生成的),因此我們必須手動糾正智哀,將Cat.prototype對象的constructor值改為Cat次询。這就是第二行的意思。

這是很重要的一點瓷叫,編程時務必要遵守屯吊。下文都遵循這一點送巡,即如果替換了prototype對象,那么盒卸,下一步必然是為新的prototype對象加上constructor屬性骗爆,并將這個屬性指回原來的構造函數(shù)。

3蔽介、 直接繼承PROTOTYPE

第三種方法是對第二種方法的改進淮腾。由于Animal對象中,不變的屬性都可以直接寫入Animal.prototype屉佳。所以谷朝,我們也可以讓Cat()跳過 Animal(),直接繼承Animal.prototype武花。

現(xiàn)在圆凰,我們先將Animal對象改寫:

然后,將Cat的prototype對象体箕,然后指向Animal的prototype對象专钉,這樣就完成了繼承。

與前一種方法相比累铅,這樣做的優(yōu)點是效率比較高(不用執(zhí)行和建立Animal的實例了)跃须,比較省內(nèi)存。

缺點是 Cat.prototype和Animal.prototype現(xiàn)在指向了同一個對象娃兽,那么任何對Cat.prototype的修改菇民,都會反映到Animal.prototype。

4投储、 利用空對象作為中介

由于"直接繼承prototype"存在上述的缺點第练,所以就有第四種方法,利用一個空對象作為中介玛荞。

F是空對象娇掏,所以幾乎不占內(nèi)存。這時勋眯,修改Cat的prototype對象婴梧,就不會影響到Animal的prototype對象。

我們將上面的方法客蹋,封裝成一個函數(shù)塞蹭,便于使用。

使用的時候嚼酝,方法如下

5浮还、 拷貝繼承

上面是采用prototype對象竟坛,實現(xiàn)繼承闽巩。我們也可以換一種思路钧舌,純粹采用"拷貝"方法實現(xiàn)繼承。簡單說涎跨,如果把父對象的所有屬性和方法洼冻,拷貝進子對象,不也能夠實現(xiàn)繼承嗎隅很?這樣我們就有了第五種方法撞牢。

首先,還是把Animal的所有不變屬性叔营,都放到它的prototype對象上屋彪。

然后,再寫一個函數(shù)绒尊,實現(xiàn)屬性拷貝的目的畜挥。

這個函數(shù)的作用,就是將父對象的prototype對象中的屬性婴谱,一一拷貝給Child對象的prototype對象蟹但。

使用的時候,這樣寫:

五谭羔、編碼實戰(zhàn)

六华糖、擴展思考

面向過程到面向對象思維如何轉變?

當我們習慣了面向過程編程時瘟裸,發(fā)現(xiàn)在程序過程中到處找不到需要面向對象的地方客叉,最主要的原因,是思維沒有轉變话告。程序員通常在拿到一個需求的時候十办,第一個反應就是如何實現(xiàn)這個需求,這是典型的面向過程的思維過程超棺,而且很快可能就實現(xiàn)了它向族。而面向對象,面對的卻是客體棠绘,第一步不是考慮如何實現(xiàn)需求件相,而是進行需求分析,就是根據(jù)需求找到其中的客體氧苍,再找到這些客體之間的聯(lián)系夜矗。

七、更多討論

討論點一让虐、如何不使用構造函數(shù)實現(xiàn)繼承紊撕?

討論點二、還有哪些實現(xiàn)封裝的方法赡突?

討論點三对扶、還有哪些實現(xiàn)繼承的方法区赵?

八、參考文獻

參考一:阮一峰——Javascript 面向對象編程


最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末浪南,一起剝皮案震驚了整個濱河市笼才,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌络凿,老刑警劉巖骡送,帶你破解...
    沈念sama閱讀 217,826評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異絮记,居然都是意外死亡摔踱,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,968評論 3 395
  • 文/潘曉璐 我一進店門怨愤,熙熙樓的掌柜王于貴愁眉苦臉地迎上來昌渤,“玉大人,你說我怎么就攤上這事憔四“蛳ⅲ” “怎么了?”我有些...
    開封第一講書人閱讀 164,234評論 0 354
  • 文/不壞的土叔 我叫張陵了赵,是天一觀的道長潜支。 經(jīng)常有香客問我,道長柿汛,這世上最難降的妖魔是什么冗酿? 我笑而不...
    開封第一講書人閱讀 58,562評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮络断,結果婚禮上裁替,老公的妹妹穿的比我還像新娘。我一直安慰自己貌笨,他們只是感情好弱判,可當我...
    茶點故事閱讀 67,611評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著锥惋,像睡著了一般昌腰。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上膀跌,一...
    開封第一講書人閱讀 51,482評論 1 302
  • 那天遭商,我揣著相機與錄音,去河邊找鬼捅伤。 笑死劫流,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播祠汇,決...
    沈念sama閱讀 40,271評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼仍秤,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了座哩?” 一聲冷哼從身側響起徒扶,我...
    開封第一講書人閱讀 39,166評論 0 276
  • 序言:老撾萬榮一對情侶失蹤粮彤,失蹤者是張志新(化名)和其女友劉穎根穷,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體导坟,經(jīng)...
    沈念sama閱讀 45,608評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡屿良,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,814評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了惫周。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片尘惧。...
    茶點故事閱讀 39,926評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖递递,靈堂內(nèi)的尸體忽然破棺而出喷橙,到底是詐尸還是另有隱情,我是刑警寧澤登舞,帶...
    沈念sama閱讀 35,644評論 5 346
  • 正文 年R本政府宣布贰逾,位于F島的核電站,受9級特大地震影響菠秒,放射性物質發(fā)生泄漏疙剑。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,249評論 3 329
  • 文/蒙蒙 一践叠、第九天 我趴在偏房一處隱蔽的房頂上張望言缤。 院中可真熱鬧,春花似錦禁灼、人聲如沸管挟。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,866評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽哮独。三九已至,卻和暖如春察藐,著一層夾襖步出監(jiān)牢的瞬間皮璧,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,991評論 1 269
  • 我被黑心中介騙來泰國打工分飞, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留悴务,地道東北人。 一個月前我還...
    沈念sama閱讀 48,063評論 3 370
  • 正文 我出身青樓,卻偏偏與公主長得像讯檐,于是被迫代替她去往敵國和親羡疗。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,871評論 2 354

推薦閱讀更多精彩內(nèi)容