多態(tài)、封裝蟹地、繼承

多態(tài)

同一個(gè)操作作用于不同的對(duì)象积暖,得到不同的結(jié)果。
重點(diǎn)分離:做什么 和 誰去做怪与。
鴨子辯型:如果它走起路來像鴨子夺刑,叫起來也是鴨子,那么它就是鴨子分别。

// 做什么
function sayName( people ) {
    people.sayName()
}

// 誰去做
const xiaoming = {
    name: '小明',
    sayName() {
        console.log( this.name )
    }
}

const lihong = {
    name: '李紅',
    sayName() {
        console.log( this.name )
    }
}

// 同一個(gè)操作作用在不同的對(duì)象
sayName( xiaoming )  // 小明
sayName( lihong )  // 李紅

封裝

只讓別人知道你想讓別人知道的遍愿,不讓別人知道你不想讓別人知道的。
封裝的目的是將信息隱藏耘斩,數(shù)據(jù)沼填、類型、實(shí)現(xiàn)括授、變化都能封裝倾哺。

  • 封裝數(shù)據(jù)

Javascript 中要達(dá)到封裝的目的轧邪,只有通過創(chuàng)建作用域來達(dá)到隱藏的目的。

const xiaoming = ( function() {
// 封裝私有數(shù)據(jù)羞海,變量命名前綴加_下劃線是潛規(guī)則,表示是私有的
 const _name = '小明',
     _age = 22
// 向外界提供公共方法
  return {
    getName() { return _name },
    getAge() { return _age }
  }
})()

xiaoming.getName()  // '小明'
xiaoming.getAge()  // 22
xiaoming._name  // undefined
xiaoming._age  // undefined
  • 封裝類型

Javascript是弱類型語(yǔ)言曲管,封裝類型沒多大意義却邓。(完)

  • 封裝實(shí)現(xiàn)

對(duì)象只需要對(duì)外提供一個(gè)固定的接口,而內(nèi)部如何實(shí)現(xiàn)這個(gè)接口院水,對(duì)外界來說應(yīng)該是透明的腊徙,外界不用關(guān)心這個(gè)對(duì)象內(nèi)部如何去實(shí)現(xiàn)這個(gè)接口,外界只需要調(diào)用這個(gè)接口就行了檬某。只要這個(gè)接口不變撬腾,內(nèi)部的實(shí)現(xiàn)如何去改變都不會(huì)影響外界。只要你打一個(gè)電話給我恢恼,你都會(huì)得到我送給你的一顆同品牌同口味同款式的棒棒糖民傻,你不用管我怎么得到這顆棒棒糖,你想吃的時(shí)候只需要打一個(gè)電話給我就好了嘿嘿嘿场斑。

/**
 * 有一個(gè) obj對(duì)象漓踢,這個(gè)對(duì)象有一個(gè)接口
 * 外界只要調(diào)用這個(gè)接口,就會(huì)返回一個(gè)數(shù)字 666
 * 接口的實(shí)現(xiàn)對(duì)于外界來說是透明的漏隐,外界只需調(diào)用接口
 */
const obj = ( function() {
  let _num = 666
  return {
    generate666() { return _num }
  }
})()

// 外界只需要調(diào)用這個(gè)對(duì)象的generate666接口就行了
obj.generate666()  // 666

/**
 * 某天這個(gè)對(duì)象的內(nèi)部實(shí)現(xiàn)改了喧半,但是接口沒有改
 * 依舊是對(duì)外返回一個(gè)數(shù)字 666
 */
const obj = ( function() {
  let _num = 600 + 60 + 6
  return {
    generate666() { return _num }
  }
})()

// 外界依舊只是調(diào)用這個(gè)對(duì)象的generate666接口就行了
obj.generate666()  // 666
  • 封裝變化:

考慮你的設(shè)計(jì)中哪些地方可能變化,這種方式與關(guān)注會(huì)導(dǎo)致重新設(shè)計(jì)的原因相反青责。它不是考慮什么時(shí)候會(huì)迫使你的設(shè)計(jì)改變挺据,而是考慮你怎樣才能夠在不重新設(shè)計(jì)的情況下進(jìn)行改變。這里的關(guān)鍵在于封裝發(fā)生變化的概念脖隶,這是許多設(shè)計(jì)模式的主題扁耐。
----《設(shè)計(jì)模式》

找到變化的東西,封裝起來浩村,和不變的分開做葵。這樣就能夠容易地把變化的東西替換掉。

繼承

順藤摸瓜圖

Javascript 是基于原型的語(yǔ)言心墅,沒有類的概念酿矢。但是你可以用類的概念去理解,實(shí)際上在 Javascript 中怎燥,“類”也是一個(gè)對(duì)象瘫筐。
原型模式是一種設(shè)計(jì)模式,也是一種編程泛型铐姚。
在諸如 JAVA 或者 Python 這種以類為中心的面向?qū)ο蟮恼Z(yǔ)言來說策肝,類和對(duì)象的關(guān)系就像是設(shè)計(jì)圖和成品的關(guān)系肛捍。要?jiǎng)?chuàng)造成品(對(duì)象),就先設(shè)計(jì)圖紙(類)之众,然后按照?qǐng)D紙(類)制造出(new)成品(對(duì)象)拙毫。
而在 Javascript 中,雖然有 new 這個(gè)關(guān)鍵字棺禾,但是他做的事情和 JAVA 或者 Python 做的事情不一樣缀蹄。
Javascript 中 new 做的事情是通過找到一個(gè)對(duì)象的原型進(jìn)行克隆,獲得新對(duì)象膘婶。
Javascript 中絕大部分?jǐn)?shù)據(jù)都是對(duì)象缺前,根對(duì)象是 Object.prototype,所有對(duì)象都克隆這個(gè)根對(duì)象悬襟。

// 所有對(duì)象都克隆 Object.prototype
const o1 = {}
const o2 = new Object()

Object.getPrototypeOf( o1 ) === Object.prototype  // true
Object.getPrototypeOf( o2 ) === Object.prototype  // true

// 如果在 Object.prototype 上增加一個(gè)屬性衅码,那么所有對(duì)象都會(huì)增加這個(gè)屬性
Object.prototype.six = 666

const o3 = {}
const o4 = new Object()
const o5 = new Date()
const o6 = new Number( 66 )

o3.six  // 666
o4.six  // 666
o5.six  // 666
o6.six  // 666

要?jiǎng)?chuàng)建一個(gè)新對(duì)象,不是通過實(shí)例化類脊岳,而是找到一個(gè)原型對(duì)象進(jìn)行克隆逝段,得到新對(duì)象。
而在現(xiàn)代瀏覽器中逸绎,都會(huì)向外暴露一個(gè) __proto__ 屬性(在ECMA規(guī)范中的描述是 [[ Prototype ]])惹恃,這個(gè)屬性指向這個(gè)對(duì)象的原型對(duì)象。原型對(duì)象會(huì)有一個(gè) constructor 屬性來存儲(chǔ)它的構(gòu)造函數(shù)名棺牧。
這樣在訪問一個(gè)對(duì)象的時(shí)候旨巷,如果本身有屬性截歉,就返回本身的屬性肪跋,如果沒有腊脱,對(duì)象會(huì)去它的原型對(duì)象上找這個(gè)屬性,如果原型對(duì)象上還沒有乏悄,又會(huì)去原型對(duì)象的原型對(duì)象找浙值,一層一層找,如果你愿意一層一層一層地?fù)荛_原型對(duì)象的屬性檩小,直到盡頭 null开呐。如果找不到了,你會(huì)發(fā)現(xiàn)规求,你會(huì)流淚筐付,就返回 undefined。這不就是原型鏈的原理嗎嘿嘿嘿阻肿。
這個(gè)克隆的過程是引擎幫忙實(shí)現(xiàn)的瓦戚。但是我們也可以實(shí)現(xiàn)一下 new 的過程。

function A() {
  this.ownNum = 666
  this.ownFn = function() { console.log(123) }
}
A.prototype.protoNum = 888
A.prototype.protoFn =  function() { console.log(456) }
A.prototype.constructor = A  // 隱含屬性丛塌,無需設(shè)置

const a = new A()
a.constructor === A  // true
a.__proto__ === A.prototype  // true

/** new 的過程 **/
// 克隆 Object.prototype
const o1 = new Object()

// 讓 o1 的 [[ Prototype ]] 指針指向一個(gè)原型對(duì)象
o1.__proto__ = A.prototype

// A.call( o1 ):給 o1 設(shè)置新的屬性较解,o1可能被改變(取決于 A構(gòu)造函數(shù) 中是否使用了 this)
// o2 = A.call( o1 ):A 構(gòu)造函數(shù)可能直接 return 一個(gè)新對(duì)象畜疾,而不是默認(rèn) return 構(gòu)造出來的 o1 對(duì)象
// 比如 function A() { ... return {b: 9} },那么在 new A() 之后返回的是 { b: 9 }印衔,而不是默認(rèn)的 o1
const o2 = A.call( o1 )

// 總是返回一個(gè)這個(gè)新建的對(duì)象
// 無論是 o1 還是 { b: 9 }啡捶,如果有 { b: 9 },那么這個(gè)的優(yōu)先級(jí)是最高的
return typeof o2 === 'object' ? o2 : o1

而這上述所有過程涉及到的繼承是這樣的:(每一個(gè)函數(shù)都有 prototype 屬性)

/*-------------------< 代碼的層面 >---------------------*/
// 引擎實(shí)現(xiàn)的代碼 [native code]
function Object() {}
Object.prototype.xx = xx

// 引擎實(shí)現(xiàn)的代碼 [native code]
function Function() {}
Function.prototype.yy = yy

// 用戶編寫的代碼
function A() {}
A.prototype.zz = zz

// new一個(gè)對(duì)象
const a = new A()
/*-------------------< 代碼的層面 />---------------------*/

/*-------------------< 背后的邏輯 >---------------------*/
a.__proto__ => A.prototype

A.__proto__ => Function.prototype  // typeof A === 'function'
A.prototype.constructor => A 
A.prototype.__proto__ => Object.prototype  // typeof A.prototype === 'object'

Function.__proto__ => Object.prototype
Function.prototype.constructor => Function
Function.prototype.__proto__ => Object.prototype  // typeof Function.prototype === 'function'

Object.__proto__ => Function.prototype  // typeof Object === 'function'
Object.prototype.constructor => Object
Object.prototype.__proto__ => null
/*-------------------< 背后的邏輯 />---------------------*/

在訪問 a 的時(shí)候奸焙,如果本身有想要的屬性届慈,就會(huì)返回本身的屬性,此時(shí)用 a.hasOwnProperty( 'a自有屬性' ) 進(jìn)行屬性檢測(cè)是返回 true 忿偷。如果 a 本身的自有屬性沒有,此時(shí)就展現(xiàn)原型鏈的作用了臊泌。a會(huì)通過 a.__proto__ 訪問到 A.prototype 鲤桥,在 A.prototype 找到了就返回,如果還沒找到渠概,就繼續(xù)一直往下找茶凳,直到終點(diǎn) null ,還沒找到播揪,就返回 undefined 贮喧。

可以說,最初的時(shí)候猪狈,每一個(gè)對(duì)象都是一樣的箱沦,都是從 Object.prototype 上克隆而來,都是空白的雇庙。但是 Javascript 的世界是繽紛多彩的谓形,大家都一樣就沒什么意思了。
于是有些對(duì)象被人為(引擎)增加了 length 長(zhǎng)度的數(shù)據(jù)屬性疆前,有了 push 寒跳、shift 等方法屬性,再用語(yǔ)法層面的 [] 符號(hào)表示竹椒,就成為了定義中的數(shù)組童太,即Array

function Array() {
  this.length = xxx
}
Array.prototype.push = function() {}
Array.prototype.shift = function() {}

var arr = []
// 等價(jià)
var arr = new Array()

是不是和 function A() {} 的套路很像?是的胸完。
同樣道理书释,Date 對(duì)象也是如此,因?yàn)檫@個(gè)對(duì)象有了 GMT 時(shí)間的數(shù)據(jù)屬性等舶吗,又有了 getDay征冷、getMonth 等方法,就成了定義中的日期對(duì)象誓琼。
Javascript 的繼承的另一種理解检激,更像是“借用”肴捉。類似 Object.prototype.toString.call( ... )
繼承的本質(zhì)是改變這個(gè)對(duì)象的 __proto__ 指向叔收。
一個(gè)對(duì)象有兩種屬性齿穗,自有屬性和繼承屬性。自有屬性就是本身自己身上有的東西饺律,訪問之后直接就給你返回的窃页,繼承屬性其實(shí)算是借用的屬性,是通過訪問自身的 __proto__ 的指向?qū)ο髮傩愿幢簦@時(shí)候已經(jīng)是在訪問其他對(duì)象了脖卖,不是自己的屬性。
就好比如兩個(gè)對(duì)象其實(shí)是不認(rèn)識(shí)巧颈,不相關(guān)的畦木,但是你把 A對(duì)象 的 proto 屬性改為 B對(duì)象,這兩個(gè)對(duì)象就產(chǎn)生了關(guān)系砸泛,這時(shí)候你也可以稱為繼承十籍。
這種理解和其他基于 CLASS 類與對(duì)象的繼承有很大的區(qū)別。
此外唇礁,繼承也是代碼重用的手段勾栗,Javascript 中的繼承不是通過嚴(yán)格意義上的拓展父類來實(shí)現(xiàn)的,而是通過原型實(shí)現(xiàn)的盏筐。
形如 Photoshop围俘,一般都不會(huì)直接操作原始圖層,都會(huì)復(fù)制(克禄稀)一份圖層楷拳,在復(fù)制的圖層上進(jìn)行編輯。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末吏奸,一起剝皮案震驚了整個(gè)濱河市欢揖,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌奋蔚,老刑警劉巖她混,帶你破解...
    沈念sama閱讀 217,826評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異泊碑,居然都是意外死亡坤按,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,968評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門馒过,熙熙樓的掌柜王于貴愁眉苦臉地迎上來臭脓,“玉大人,你說我怎么就攤上這事腹忽±蠢郏” “怎么了砚作?”我有些...
    開封第一講書人閱讀 164,234評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)嘹锁。 經(jīng)常有香客問我葫录,道長(zhǎng),這世上最難降的妖魔是什么领猾? 我笑而不...
    開封第一講書人閱讀 58,562評(píng)論 1 293
  • 正文 為了忘掉前任米同,我火速辦了婚禮,結(jié)果婚禮上摔竿,老公的妹妹穿的比我還像新娘面粮。我一直安慰自己,他們只是感情好继低,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,611評(píng)論 6 392
  • 文/花漫 我一把揭開白布但金。 她就那樣靜靜地躺著,像睡著了一般郁季。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上钱磅,一...
    開封第一講書人閱讀 51,482評(píng)論 1 302
  • 那天梦裂,我揣著相機(jī)與錄音,去河邊找鬼盖淡。 笑死年柠,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的褪迟。 我是一名探鬼主播冗恨,決...
    沈念sama閱讀 40,271評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼味赃!你這毒婦竟也來了掀抹?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,166評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤心俗,失蹤者是張志新(化名)和其女友劉穎傲武,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體城榛,經(jīng)...
    沈念sama閱讀 45,608評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡揪利,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,814評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了狠持。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片疟位。...
    茶點(diǎn)故事閱讀 39,926評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖喘垂,靈堂內(nèi)的尸體忽然破棺而出甜刻,到底是詐尸還是另有隱情绍撞,我是刑警寧澤,帶...
    沈念sama閱讀 35,644評(píng)論 5 346
  • 正文 年R本政府宣布罢吃,位于F島的核電站楚午,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏尿招。R本人自食惡果不足惜矾柜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,249評(píng)論 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望就谜。 院中可真熱鬧怪蔑,春花似錦、人聲如沸丧荐。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,866評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)虹统。三九已至弓坞,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間车荔,已是汗流浹背渡冻。 一陣腳步聲響...
    開封第一講書人閱讀 32,991評(píng)論 1 269
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留忧便,地道東北人族吻。 一個(gè)月前我還...
    沈念sama閱讀 48,063評(píng)論 3 370
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像珠增,于是被迫代替她去往敵國(guó)和親超歌。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,871評(píng)論 2 354

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

  • 1.封裝 封裝的定義: 首先是抽象蒂教,把事物抽象成一個(gè)類巍举,其次才是封裝,將事物擁有的屬性和動(dòng)作隱藏起來凝垛,只保留特定的...
    時(shí)待吾閱讀 407評(píng)論 0 1
  • 官方中文版原文鏈接 感謝社區(qū)中各位的大力支持禀综,譯者再次奉上一點(diǎn)點(diǎn)福利:阿里云產(chǎn)品券,享受所有官網(wǎng)優(yōu)惠苔严,并抽取幸運(yùn)大...
    HetfieldJoe閱讀 2,998評(píng)論 4 14
  • 特別說明定枷,為便于查閱,文章轉(zhuǎn)自https://github.com/getify/You-Dont-Know-JS...
    殺破狼real閱讀 1,138評(píng)論 0 4
  • 博客內(nèi)容:什么是面向?qū)ο鬄槭裁匆嫦驅(qū)ο竺嫦驅(qū)ο缶幊痰奶匦院驮瓌t理解對(duì)象屬性創(chuàng)建對(duì)象繼承 什么是面向?qū)ο?面向?qū)ο?..
    _Dot912閱讀 1,424評(píng)論 3 12
  • 剛開始看到這個(gè)的時(shí)候届氢,覺得自己肯定寫不好欠窒,一直不敢聯(lián)系,終于鼓起勇氣寫了一張。 有待加強(qiáng)練習(xí)
    Dr米莎閱讀 149評(píng)論 0 0