最美情侣中文字幕电影,在线麻豆精品传媒,在线网站高清黄,久久黄色视频

歡迎光臨散文網(wǎng) 會(huì)員登陸 & 注冊(cè)

【D1n910】學(xué)習(xí)《JavaScript 設(shè)計(jì)模式》(1[2/2]/6)

2021-02-13 02:33 作者:愛(ài)交作業(yè)的D1N910  | 我要投稿

正常操作,正常分析,大家好,我是D1n910。

今天繼續(xù)來(lái)學(xué)習(xí) 《JavaScript 設(shè)計(jì)模式》的第一篇 第2章 寫(xiě)的都是看到的——面向?qū)ο缶幊獭?/p>

這是一個(gè)連續(xù)的讀書(shū)筆記,所以如果你之前的內(nèi)容沒(méi)有看的話,請(qǐng)務(wù)必一定要去看。

快速入口 ??


這里再次感謝 《Javascript 設(shè)計(jì)模式》及其作者 張榮銘,專(zhuān)欄內(nèi)容是在它的基礎(chǔ)上生成的。

第一篇 面向?qū)ο缶幊?/span>

第 2?章?寫(xiě)的都是看到的——面向?qū)ο缶幊?/p>


來(lái)公司工作,小新很想知道具體工作是怎么做的。項(xiàng)目經(jīng)理帶小新看項(xiàng)目,但是小新發(fā)現(xiàn)這些項(xiàng)目里的都是一個(gè)個(gè)對(duì)象。


2.1、兩種編程風(fēng)格 —— 面向過(guò)程與面向?qū)ο?/strong>

小新發(fā)現(xiàn)一個(gè)情況就是,大家都是創(chuàng)建對(duì)象來(lái)完成任務(wù)內(nèi)容,而不是直接寫(xiě)函數(shù),這是為什么呢?


在小新看來(lái)的需求開(kāi)發(fā)方式,以從深圳到上海為例子。


小新會(huì)這么做:

(1)一個(gè)容器能夠載人

(2)發(fā)動(dòng)機(jī)能夠推動(dòng)容器

(3)四個(gè)輪子能夠更好地推動(dòng)容器


對(duì)于小新B來(lái)說(shuō),他覺(jué)得兩個(gè)大輪子更好,所以他的函數(shù)方法又會(huì)變成這樣。


對(duì)于小新C來(lái)說(shuō),他認(rèn)為發(fā)動(dòng)機(jī)大會(huì)更好,所以他的函數(shù)方法會(huì)變成這樣。


實(shí)際上為了同一個(gè)類(lèi)似的目的,三個(gè)開(kāi)發(fā)人員寫(xiě)了自己的三套方法,而且都是要從頭寫(xiě),在代碼內(nèi)容也都不盡相同的。


我們是根據(jù)需求任務(wù)來(lái)設(shè)置全局變量、函數(shù)。這種就是面向過(guò)程開(kāi)發(fā)。

只是為了能夠?qū)崿F(xiàn)【從深圳->上?!窟^(guò)程而開(kāi)發(fā)。

也許同一個(gè)【從深圳->上?!啃枨螅煌?xiàng)目里,不同的人實(shí)現(xiàn)方式不一一樣;

也許同一個(gè)項(xiàng)目里,同一個(gè)人,不同的需求【五天從深圳->上?!俊ⅰ救鞆纳钲?>上?!?,最終的實(shí)現(xiàn)方式也不一一樣。


但是在現(xiàn)代企業(yè)項(xiàng)目里,會(huì)把這些內(nèi)容封裝起來(lái),變成一輛對(duì)象——車(chē)。

在我們這個(gè)例子里,為了讓這輛車(chē)能夠?qū)崿F(xiàn)從深圳 -> 上海。

可以設(shè)定這輛車(chē)的發(fā)動(dòng)機(jī)性能;

這輛車(chē)能夠載多少多少的人;

……

這輛車(chē)自帶智能內(nèi)容,能夠根據(jù)我們的需要調(diào)配自己內(nèi)部的內(nèi)容,而不需要我們每次從零開(kāi)發(fā)一個(gè)發(fā)動(dòng)機(jī)、容器、輪子。

有時(shí)候這輛車(chē)不能夠滿(mǎn)足現(xiàn)有的需求任務(wù),比如我們要求能夠裝載1000個(gè)客人,這輛車(chē)最多只能變成能夠裝500個(gè)客人的。

那需要我們是根據(jù)需求任務(wù),對(duì)對(duì)象車(chē)進(jìn)行改造,變成能夠支持轉(zhuǎn)載1000個(gè)客人的車(chē)。

這就是面向?qū)ο蠖_(kāi)發(fā)。


2.2、包裝明星——封裝(P12)

2.2.1 創(chuàng)建一個(gè)類(lèi)(P12)

在上面的例子中,我們舉了一個(gè)很形象的例子,就是車(chē)。

現(xiàn)實(shí)社會(huì)中,有工程師設(shè)計(jì)出車(chē)的圖紙,然后交付給工廠生產(chǎn)出能夠使用的一輛輛車(chē)。

那么在Javascript中,我們想要?jiǎng)?chuàng)建和使用對(duì)象,首先就要?jiǎng)?chuàng)建一個(gè)Javascript里的圖紙,也就是類(lèi),Class。

(現(xiàn)在最新的 Javascript 支持直接用 Class 關(guān)鍵字來(lái)聲明類(lèi),可以自行查閱)


Javascript 創(chuàng)建類(lèi)很簡(jiǎn)單。有幾個(gè)關(guān)鍵點(diǎn)。

(1)聲明一個(gè)函數(shù)保存在一個(gè)變量里;

(2)這個(gè)類(lèi)的變量名首字母一般是大寫(xiě)的,這是編程界的習(xí)俗,如果不這么做的話,會(huì)被綁到柱子上燒死(開(kāi)玩笑的);

(3)在(1)聲明的函數(shù)的內(nèi)部,對(duì)this(函數(shù)內(nèi)部自帶的變量,用于指向當(dāng)前這個(gè)對(duì)象)添加屬性或者方法來(lái)實(shí)現(xiàn)對(duì)類(lèi)添加屬性或者方法。


像下面這樣,我們就可以創(chuàng)建一個(gè)車(chē)類(lèi),Car。


var Car = function(id, carName, color) {

? ? this.id = id;

? ? this.carName = carName;

? ? this.color = color

}


創(chuàng)建時(shí)接收三個(gè)參數(shù),id、carName、color,然后復(fù)制給車(chē)對(duì)象上。


類(lèi)的屬性、方法還可以通過(guò)我們上一篇的 prototype 來(lái)實(shí)現(xiàn)添加。


這里有兩種方式,一種是給類(lèi)的 prototype 的屬性賦值,一種是直接講一個(gè)對(duì)象賦值給類(lèi)的 prototype。


這兩種要注意不能混用。


方法一、

Car.prototype.carWheelNum = 4


方法二、

Car.prototype =?{

????carWheelNum: 4

}


創(chuàng)建好我們的類(lèi)后,我們封裝好了屬性、方法在里面,并不是能夠直接拿來(lái)用的。


類(lèi)相當(dāng)于咱們的圖紙,想要使用就像按照?qǐng)D紙生成具體的車(chē)一樣,我們也要按照類(lèi)生成具體的對(duì)象才能夠用類(lèi)里封裝的屬性和方法。


在 Javascript 中,我們用 new 關(guān)鍵字來(lái)實(shí)例化(創(chuàng)建)新的對(duì)象,然后就可以用點(diǎn)語(yǔ)法來(lái)訪問(wèn)對(duì)象的屬性?xún)?nèi)容了。


var baoma = new Car(1, '寶馬', 'red')

baoma.id // 1


用 this 添加的屬性和方法和用 prototype 添加的有什么不一樣嗎?


用?this?添加的屬性和方法是創(chuàng)建出來(lái)的每個(gè)對(duì)象獨(dú)有的,new 一個(gè)新的對(duì)象的時(shí)候會(huì)按照類(lèi)的內(nèi)容跑一邊屬性的賦值,所以每次new一個(gè)新的對(duì)象,都會(huì)重新跑一邊,重新賦值;


用?prototype?添加的屬性和方法是每個(gè)對(duì)象共有的,每創(chuàng)建一個(gè)新的對(duì)象,不需要重新賦值屬性和方法。


向上面的車(chē)輪數(shù)就是共有的。


這里的原理:

JavaScript 在用點(diǎn)語(yǔ)法找一個(gè)對(duì)象上的屬性時(shí),如果當(dāng)前的對(duì)象找不到,就會(huì)按照原型鏈,往對(duì)象的 _proto_ 屬性指向的對(duì)象上找,直到?jīng)]有原型鏈找不到要的屬性了,就返回 undefined。


對(duì)象的?_proto_? 屬性指向的對(duì)象等于類(lèi)的 prototype 指向的對(duì)象。


所有根據(jù)同一個(gè)類(lèi)實(shí)例化的對(duì)象都是擁有同一個(gè) _proto_ 指向的屬性。


像我們剛剛的例子,

首先從視覺(jué)上的信息,我們就知道知道對(duì)象的?_proto_? 屬性指向的對(duì)象等于類(lèi)的 prototype 指向的對(duì)象,其次,也能通過(guò)等式判斷是否相等。


這些內(nèi)容可以在我之前的文章中看到更多的內(nèi)容


這也是上一篇見(jiàn)過(guò)的內(nèi)容,也是說(shuō)了要看的內(nèi)容,如果你沒(méi)去看的話,那就是你是大壞蛋!




2.2.2、這些都是我的——屬性與方法封裝(p12)

知道了怎么創(chuàng)建一個(gè)類(lèi)以后,我們要具體理清楚類(lèi)和對(duì)象中的屬性與方法。什么意思呢。


面向?qū)ο蟮母拍罾?,我們?huì)對(duì)屬性和方法進(jìn)行隱藏和暴露,就會(huì)牽扯出 私有屬性、私有方法等。


還是以車(chē)為例子,我們先看看面向?qū)ο髸r(shí)會(huì)考慮的東西。


我們可以直接看到車(chē)的品牌、車(chē)牌號(hào)、車(chē)身顏色,這都是車(chē)子直接暴露出來(lái)的,用戶(hù)可以直接了解到的。


車(chē)子的速度是車(chē)子的一個(gè)屬性,我們可以用車(chē)子暴露出來(lái)的公共方法——踩油門(mén),去改變車(chē)子的速度。


還有一些東西,我們是基本上不會(huì)知道的,車(chē)子也不會(huì)希望告訴我們的,比如車(chē)子的實(shí)際成本價(jià)格。


根據(jù)上面的內(nèi)容,羅列了 JavaScript 中類(lèi)中對(duì)象能夠用到的屬性和方法

對(duì)象公有屬性,對(duì)象公有方法

定義:能夠被外部直接訪問(wèn)到

來(lái)源:只用 this 創(chuàng)建的屬性和方法


私有屬性,私有方法

定義:只能在類(lèi)內(nèi)創(chuàng)建的特權(quán)方法、構(gòu)造時(shí)訪問(wèn)使用

來(lái)源:在類(lèi)中直接聲明的屬性、方法


特權(quán)方法(本身是對(duì)象公有方法)

定義:能夠被外部訪問(wèn),同時(shí)能夠訪問(wèn)私有屬性,私有方法

來(lái)源:只用 this 創(chuàng)建的方法


構(gòu)造器

定義:在實(shí)例化對(duì)象時(shí),會(huì)調(diào)用的特權(quán)方法

來(lái)源:同定義


下面查看例子


var?Book?=?function(id,?name,?price){

??//?私有屬性

??var?num?=?1;

??//?私有方法

??function?checkId?()?{


??};

??//?特權(quán)方法

??this.getName?=?function?()?{

????console.log(name)

??};

??this.addPrice?=?function?()?{

????price?++

??}

??this.getPrice?=?function?()?{

????console.log(price)

??};

??//?對(duì)象公有屬性

??this.id?=?id;

??//?對(duì)象公有方法

??this.copy?=?function?()?{};

??//?構(gòu)造器

??this.addPrice()

}


除了上面這些意外,還有下面的這幾種屬性


類(lèi)靜態(tài)公有屬性,類(lèi)靜態(tài)公有方法(對(duì)象不能訪問(wèn))

定義:在外部能夠直接用點(diǎn)語(yǔ)法訪問(wèn)類(lèi)的屬性

來(lái)源:在類(lèi)上用點(diǎn)語(yǔ)法定義的屬性和方法


公有屬性,公有方法

定義:所有的對(duì)象公用的內(nèi)容

來(lái)源:在類(lèi)上用 prototype 來(lái)進(jìn)行定義


示例:


//?類(lèi)靜態(tài)公有屬性

Book.isChinese?=?yes;


//?類(lèi)靜態(tài)公有方法

Book.resetTime?=?function()?{

??console.log('resetTime')

}


Book.prototype?=?{

??//?公有屬性

??isJSBook:?false,

??//?公有方法

??dispaly:?function()

}


公有屬性,公有方法

定義:能夠被所有的對(duì)象使用

來(lái)源:在類(lèi)上用 prorotype 定義的屬性和方法


這里要牢記的是,這里的方法作用其實(shí)就是看 new 對(duì)象時(shí),對(duì) this 的作用,就可以很方便地區(qū)分啦。


2.2.3、你們看不到我——閉包實(shí)現(xiàn)(P15)

上面我們說(shuō)了,可以利用類(lèi)的點(diǎn)語(yǔ)法來(lái)實(shí)現(xiàn)

類(lèi)靜態(tài)公有屬性,類(lèi)靜態(tài)公有方法(對(duì)象不能訪問(wèn))

現(xiàn)在我們想實(shí)現(xiàn)

類(lèi)靜態(tài)私有屬性,類(lèi)靜態(tài)私有方法

定義:不能夠被外部直接訪問(wèn),所有對(duì)象公用同一個(gè)內(nèi)容。


思考一下,我們就可以用閉包實(shí)現(xiàn)。


示例,實(shí)現(xiàn)記錄工程里實(shí)例化過(guò)多少本書(shū)

var Book = (function() {

????// 類(lèi)靜態(tài)私有屬性

? var bookNum = 0;

????//?類(lèi)靜態(tài)私有方法

? function getAllBookNum() {

? ? return bookNum;

? }

? return function(newName, newPrice) {

? ? this.id = bookNum++

? ? this.name = newName

? ? this.getAllBookNum = function() {

? ? ? console.log(getAllBookNum())

? ? }

? }

})()


var daxue = new Book('daxue')

var zairenjian = new Book('zairenjian')

daxue.getAllBookNum() // 2


上面做了閉包的示例。


現(xiàn)在討論一下什么是閉包。


作者給出的閉包的定義是:


閉包是有權(quán)訪問(wèn)另一個(gè)函數(shù)作用域中變量的函數(shù)。


即在一個(gè)函數(shù)內(nèi)部創(chuàng)建另外一個(gè)函數(shù)。


我覺(jué)得這個(gè)定義是優(yōu)雅恰當(dāng)?shù)摹?/p>


這里的閉包可以作為可實(shí)例化對(duì)象使用。


當(dāng)然了,直接返回構(gòu)造函數(shù)的,不太好定義類(lèi)共有屬性、公共屬性等。


所以可以改成下面這種返回類(lèi)的形式。

var Book = (function() {

? var bookNum = 0;

? function getAllBookNum() {

? ? return bookNum;

? }

? // 創(chuàng)建一個(gè)類(lèi)

? function _book (newName, newPrice) {

? ? this.id = bookNum++

? ? this.name = newName

? ? this.getAllBookNum = function() {

? ? ? console.log(getAllBookNum())

? ? }

? }

? ? _book.dd = 1

? return _book

})()


2.2.4、找位檢察長(zhǎng)——?jiǎng)?chuàng)建對(duì)象的安全模式(p17)

我們寫(xiě)函數(shù),要進(jìn)行防錯(cuò)處理,下面作者針對(duì)一般人剛接觸面向?qū)ο髮?xiě)法,忘記寫(xiě) new,寫(xiě)了一種防止報(bào)錯(cuò)的辦法。


首先看下面的舉例,直接這么看的話,ook1 因?yàn)闆](méi)有使用 new 關(guān)鍵字,是實(shí)例化失敗的

為什么 book1 是 undefined,然后我們的 this.id = id 執(zhí)行后會(huì)發(fā)生什么。


首先我們要知道 new 的這個(gè)關(guān)鍵字做了什么

new 的作用是

1.創(chuàng)建一個(gè)空對(duì)象,作為將要返回的對(duì)象實(shí)例

2.將這個(gè)空對(duì)象的原型指向構(gòu)造函數(shù)的prototype屬性

3.將構(gòu)建函數(shù)的this指針替換為在1創(chuàng)建的對(duì)象


那么我們自己實(shí)現(xiàn)一個(gè)new可以這么做

這種是 apply 的用法
這種是 call 的方法

那么了解完 new 這個(gè)關(guān)鍵字的作用以后,我們回頭過(guò)來(lái)看看剛剛的問(wèn)題。


book1 是 undefined 的原因是,因?yàn)闆](méi)有帶 new 關(guān)鍵字,所以就是直接執(zhí)行函數(shù),原 Book 函數(shù)本身沒(méi)有 return 任何東西,所以得到的當(dāng)然是默認(rèn) return undefined。


this.id = id 會(huì)發(fā)生什么?

會(huì)發(fā)現(xiàn)全局變量? window? 被污染了,多了一個(gè) id 屬性,這里是因?yàn)闆](méi)有帶 new 關(guān)鍵字,所以就是直接執(zhí)行函數(shù),那么相當(dāng)于在 window 這個(gè)對(duì)象下執(zhí)行,this會(huì)一級(jí)一級(jí)找對(duì)象,找到上一級(jí)對(duì)象就不會(huì)再繼續(xù)找,這里的對(duì)象直接就是 window,所以要添加的屬性也會(huì)被放到 window 上。


作者由此延申除了要有一個(gè)類(lèi)似檢察長(zhǎng)的東西,防止有出現(xiàn)忘記用 new 從而導(dǎo)致全局變量被污染的情況,可以這么處理。


回憶一下我們 new 做的事情的1、2、3,那么也就是說(shuō) new 執(zhí)行了的話,this?應(yīng)該是從屬于 當(dāng)前類(lèi)的。

那么可以這么判斷:

這樣就可以避免出現(xiàn)發(fā)生錯(cuò)誤的問(wèn)題了。

回憶一下 new 的過(guò)程,上面的判斷方式,我們還可以改成下面這樣的:



但是我還是建議直接把那些忘記寫(xiě) new 的人拖下去燒死。(殘忍)


2.3、傳宗接代——繼承(P19)

學(xué)到現(xiàn)在,我們都是學(xué)的如何從一個(gè)藍(lán)圖里創(chuàng)建一個(gè)實(shí)例,這個(gè)實(shí)例有的屬性和方法,都是繼承這個(gè)藍(lán)圖的。


還沒(méi)有學(xué)到如果多級(jí)繼承。


比如A創(chuàng)建太極拳四十六式,B從A處繼承了太極拳太極拳四十六式,然后往里面加入了八式,變成了太極拳五十四式。


然后C又從B處繼承到了這套太極拳五十四式。


現(xiàn)在討論如何在?Javascript 中實(shí)現(xiàn)現(xiàn)這種繼承辦法。

2.3.1、子類(lèi)的原型對(duì)象——類(lèi)式繼承(P19)

比較常見(jiàn)的是類(lèi)式繼承,方法如下

// 聲明父類(lèi)

function Taiji46() {

? ? this.Taiji46 = 46

}


// 聲明父類(lèi)共有方法

Taiji46.prototype.outPut46 = function() {

? ? return this.Taiji46

}


// 聲明子類(lèi)

function Taiji54() {

? ? this.Taiji54 = 54

}


// 子類(lèi)繼承父類(lèi)

Taiji54.prototype = new Taiji46()


// 聲明子類(lèi)共有方法

Taiji54.prototype.outPut54 = function() {

? ? return this.Taiji54

}


// 實(shí)例化太極54式親傳弟子

var taiji54dizi1 = new Taiji54()


taiji54dizi1.outPut54() // 54


taiji54dizi1.outPut46() // 46


現(xiàn)在這種類(lèi)式繼承后的對(duì)象,可以打繼承自構(gòu)建函數(shù)的拳,也可以打父類(lèi)的拳。


這里子類(lèi)實(shí)例化后的對(duì)象能夠使用父類(lèi)的屬性和方法的本質(zhì)還是和我們上面學(xué)的原型鏈有關(guān)。


通過(guò)關(guān)鍵字 instanceof 我們可以發(fā)現(xiàn),太極54式親傳弟子確實(shí)與 Taiji46、54有關(guān)

但是為什么 Taiji54 instanceof Taiji46 是 false ?


原因是?instanceof? 的作用是某個(gè)對(duì)象是否是某個(gè)類(lèi)的實(shí)例,或者說(shuō)某個(gè)對(duì)象是否繼承了某個(gè)類(lèi)。


它是按照 prototype 原型鏈判斷的。所以剛剛的如果是下面的內(nèi)容,就正確了。


再次拓展,我們可以發(fā)現(xiàn),原來(lái)所有的對(duì)象都是 Object 的實(shí)例。

Object 是所有對(duì)象的祖先。


2.3.2、創(chuàng)建即繼承——構(gòu)造函數(shù)繼承(P21)

以繼承父類(lèi)的引用類(lèi)型的屬性為例子。

比如這里有兩個(gè)親傳弟子,從父類(lèi)都知道出拳步驟是1、2、3,但是親傳弟子二號(hào)自己練的時(shí)候,非要在出拳步驟里加多個(gè)步驟2,結(jié)果發(fā)現(xiàn)這個(gè)改動(dòng)把弟子一的出拳章法也改動(dòng)了。


這就很容易埋藏陷阱。


而且按照我們剛剛的類(lèi)式繼承,我們是靠原型 prototype? 對(duì)父類(lèi)實(shí)例化來(lái)實(shí)現(xiàn)的,因此創(chuàng)建父類(lèi)的時(shí)候,是無(wú)法向父類(lèi)傳遞參數(shù)的。所以如果實(shí)例化父類(lèi)的時(shí)候,也沒(méi)有辦法對(duì)父類(lèi)的構(gòu)建函數(shù)進(jìn)行初始化。


為了解決上面兩個(gè)問(wèn)題,我們可以用構(gòu)造函數(shù)繼承。?

function Taiji46(name) {

? ? this.name = name

? ? this.Taiji46 = 46

? ? this.cqsx = [1, 2, 3]

}


// 聲明父類(lèi)共有方法

Taiji46.prototype.outPut46 = function() {

? ? return this.Taiji46

}


// 聲明子類(lèi)

function Taiji54(name) {

?????// 繼承父類(lèi)

? ? Taiji46.call(this, name)

? ? this.Taiji54 = 54

}


// 聲明子類(lèi)共有方法

Taiji54.prototype.outPut54 = function() {

? ? return this.Taiji54

}

// 實(shí)例化太極54式親傳弟子_1

var taiji54dizi_1 = new Taiji54('taiji54dizi_1')

// 實(shí)例化太極54式親傳弟子_2

var taiji54dizi_2 = new Taiji54('taiji54dizi_2')

taiji54dizi_1.name // taiji54dizi_1

taiji54dizi_2.name //?taiji54dizi_2


這里的關(guān)鍵點(diǎn)在于 cell 函數(shù)把this放到繼承的父類(lèi)里走了一遍,也就是走了構(gòu)造函數(shù),構(gòu)造了一遍。

不過(guò)這里有一個(gè)問(wèn)題在于,直接單純用構(gòu)造函數(shù)繼承的話,咱們就只能繼承到父類(lèi)的this的內(nèi)容了,父類(lèi)的 prototype 就無(wú)法使用了。


為了綜合類(lèi)式繼承和構(gòu)造函數(shù)繼承,就有了組合繼承。

2.3.3、將優(yōu)點(diǎn)為我所用——組合繼承(P22)

類(lèi)式繼承通過(guò)子類(lèi)的原型 prototype 實(shí)例化實(shí)現(xiàn)的;構(gòu)造函數(shù)繼承式通過(guò)在子類(lèi)構(gòu)造函數(shù)作用環(huán)境中執(zhí)行一次父類(lèi)的構(gòu)造函數(shù)來(lái)實(shí)現(xiàn)的。所以組合繼承就是同時(shí)實(shí)現(xiàn)了這兩點(diǎn)。

function Taiji46(name) {

? ? this.name = name

? ? this.Taiji46 = 46

? ? this.cqsx = [1, 2, 3]

}


// 聲明父類(lèi)共有方法

Taiji46.prototype.outPut46 = function() {

? ? return this.Taiji46

}


// 聲明子類(lèi)

function Taiji54(name) {

? ? Taiji46.call(this, name)

? ? this.Taiji54 = 54

}


Taiji54.prototype = new Taiji46()


// 聲明子類(lèi)共有方法

Taiji54.prototype.outPut54 = function() {

? ? return this.Taiji54

}

但是這不是最完美的版本,因?yàn)槭褂脴?gòu)造函數(shù)繼承時(shí)執(zhí)行了一遍父類(lèi)的構(gòu)造函數(shù),而在實(shí)現(xiàn)子類(lèi)原型的類(lèi)式繼承時(shí)又調(diào)用了一遍父類(lèi)構(gòu)造函數(shù)。


因此父類(lèi)構(gòu)造函數(shù)調(diào)用了兩遍,所以這還不是最完美的方式。


可惡……難道這里不可以直接Taiji54.prototype = Taiji46.prototype 嗎?

我試了一下,完全可以好吧!


2.3.4、潔凈的繼承者——原型式繼承(P22)

在學(xué)習(xí)上面說(shuō)的更好的方式之前,作者想讓我們學(xué)習(xí)一個(gè)簡(jiǎn)單而很常用的方式。


先用了道格拉斯·克洛克福德2006年發(fā)表的《Javascript 中原型式繼承》的觀點(diǎn)


“借助原型 prototype 可以根據(jù)已有的對(duì)象創(chuàng)建一個(gè)新的對(duì)象,同時(shí)也不必創(chuàng)建新的自定義對(duì)象類(lèi)型”


直接看一下大師實(shí)現(xiàn)的代碼


// 原型式繼承

function inheritObject (o) {

????// 聲明一個(gè)過(guò)度函數(shù)對(duì)象

????function F() {}

????// 過(guò)渡對(duì)象的原型繼承父對(duì)象

???? F.prototype = o;

????// 返回過(guò)渡對(duì)象的一個(gè)實(shí)例,該實(shí)例的原型繼承了父對(duì)象

????return new F();

}


這種方式和類(lèi)式繼承很像,是它封裝。所以類(lèi)式繼承有的問(wèn)題,它也有。


但是這畢竟是 2006 年的思想,隨著這個(gè)思想的深入,后面就出現(xiàn)了 Object.create() 的方法可以直接實(shí)現(xiàn)上面的內(nèi)容。

(小聲嘀咕:現(xiàn)在還有“...”的拓展方法呢)


2.3.5、如虎添翼 ——寄生式繼承(P24)

作者還說(shuō)了道格拉斯·克洛克福德更進(jìn)一步的繼承,寄生式繼承。


其實(shí)我能理解,在道格拉斯·克洛克福德那個(gè)時(shí)候,對(duì)象的復(fù)制是一個(gè)比較棘手的問(wèn)題,很容易有淺拷貝問(wèn)題。


這里的寄生式繼承,指的是在直接拷貝基礎(chǔ)對(duì)象的基礎(chǔ)上,還能添加自己的方法到拷貝出來(lái)的對(duì)象上。


//基礎(chǔ)對(duì)象

var book = {

????name: 'js book',

????alikeBook: ['css book', 'html book']

}


function createBook(obj) {

????// 通過(guò)原型式繼承創(chuàng)建新對(duì)象

????var o = new??inheritObject (book);

????// 拓展新的對(duì)象

????o.getName = function() {

????????console.log(name);

????}

????// 返回拓展后的新對(duì)象

????return o;

}


這個(gè)是對(duì)原型繼承的第二次封裝,進(jìn)行對(duì)象的拓展。


2.3.6、終極繼承者——寄生組合式繼承(P25)

之前組合式繼承留下了一個(gè)問(wèn)題在于,子類(lèi)不是父類(lèi)的實(shí)例,子類(lèi)的原型式父類(lèi)的實(shí)例,所以才有了寄生組合式繼承。

首先看一下寄生式繼承 繼承原型


function inheritPrototype(subType, superType){

? ? var p = Object.create(superType.prototype);? ? // 復(fù)制一份父類(lèi)的原型副本保存在變量中

? ? p.constructor = subType;? ? ? ? ? ? ? ? ? ? // 修正因?yàn)橹貙?xiě)子類(lèi)原型導(dǎo)致子類(lèi)的 constructor 屬性被修改。如果你不知道這一行的作用,可以屏蔽之,然后跑一邊,然后查看一下子類(lèi)的 constructor

? ? subType.prototype = p;? ? ? ? ? ? ? ? ? ? ? ? //設(shè)置子類(lèi)的原型

}


那么我們只需要把之前組合式繼承里的子類(lèi)繼承父類(lèi) prototype 由原來(lái)的類(lèi)式繼承,改成上面的寄生式繼承即可。

function Taiji46(name) {

? ? this.name = name

? ? this.Taiji46 = 46

? ? this.cqsx = [1, 2, 3]

}


// 聲明父類(lèi)共有方法

Taiji46.prototype.outPut46 = function() {

? ? return this.Taiji46

}


// 聲明子類(lèi)

function Taiji54(name) {

? ? Taiji46.call(this, name)

? ? this.Taiji54 = 54

}

// Taiji54.prototype = new Taiji46()

inheritPrototype('Taiji54', 'Taiji46')


// 聲明子類(lèi)共有方法

Taiji54.prototype.outPut54 = function() {

? ? return this.Taiji54

}


2.4、老師不止一位——多繼承(P27)

面向?qū)ο笳Z(yǔ)言會(huì)有多繼承,在Javascript中也可以實(shí)現(xiàn)。


先講解一下當(dāng)前(2015)很流行的一個(gè)用來(lái)繼承單對(duì)象屬性的 extend 方法


// 單繼承 屬性賦值

var extend = function(target, source) {

????for (var property in source) {

????????target[property] = source[property];

????}

????// 返回目標(biāo)對(duì)象

????return target

}


這種就是之前的淺拷貝。


這種可以可以用 Object.assign() 完成了,后面多個(gè)混合的實(shí)現(xiàn)多態(tài)的辦法,也是可以用Object.assign() 填入多個(gè)參數(shù)完成。


下面可以看看原生寫(xiě)法


var mix = function() {

var i = 1,

len = arguments.length,

target = arguments[0],

arg;

for(;i<len;i++) {

arg = arguments[i];

// 遍歷被繼承對(duì)象中的屬性

for (var property in arg) {

target[property] = arg[property];

}

}

// 返回目標(biāo)對(duì)象

return target

}


2.5、多種調(diào)用方式——多態(tài)(P29)

面向?qū)ο缶幊讨械亩鄳B(tài)在 Javascript 中的實(shí)現(xiàn)。


多態(tài),就是同一個(gè)方法多種調(diào)用方式。


JavaScript 本身就是很靈活,下面通過(guò) arguments 來(lái)按照傳入的參數(shù)來(lái)判斷要調(diào)用的方式。

function Add() {

// 無(wú)參數(shù)算法

function zero() {

????return 0

}

// 一個(gè)參數(shù)算法

function one(num) {

????return ?num

}

// 兩個(gè)參數(shù)算法

function two(num1, num2) {

????return num1 + num2

}

// 相加共有方法

this.add = function() {

????var arg = arguments,

len = arg.length;

switch(len) {

case 0:

return zero();

case 1:

return one(arg[0]);

case 2:

return two(arg[0], arg[1]);

}

}

}


var A = new Add();


A.add(); // 0

A.add(1); // 1

A.add(6,2); // 8


本章讀書(shū)筆記結(jié)束,也不留課后作業(yè)了,光是看完,就辛苦了!


寫(xiě)了快兩天,才寫(xiě)完。


這一波是徹底理解 JavaScript?中面向?qū)ο蟮某R?jiàn)繼承寫(xiě)法以及其發(fā)展史,希望對(duì)大家有所幫助!


別忘了??梢灾苯尤タ纯醋钚碌?Class 類(lèi)方法繼承!


End

D1n910?

2012.02.13 02:32 寫(xiě)于福永

【D1n910】學(xué)習(xí)《JavaScript 設(shè)計(jì)模式》(1[2/2]/6)的評(píng)論 (共 條)

分享到微博請(qǐng)遵守國(guó)家法律
玉林市| 梅州市| 迁安市| 新巴尔虎右旗| 丽江市| 永寿县| 金川县| 鸡东县| 金昌市| 奎屯市| 蛟河市| 漾濞| 石嘴山市| 嵊泗县| 会同县| 绥阳县| 襄城县| 兴义市| 新巴尔虎左旗| 砀山县| 永福县| 资源县| 旅游| 扎鲁特旗| 陇西县| 图们市| 沈丘县| 舞钢市| 江城| 准格尔旗| 内黄县| 安阳县| 清镇市| 乌什县| 九江县| 德州市| 疏勒县| 太湖县| 开平市| 柳河县| 平凉市|