小編給大家分享一下JavaScript 對象是什么,希望大家閱讀完這篇文章后大所收獲,下面讓我們一起去探討吧!
成都創(chuàng)新互聯(lián)專注于郊區(qū)企業(yè)網(wǎng)站建設(shè),成都響應(yīng)式網(wǎng)站建設(shè)公司,成都做商城網(wǎng)站。郊區(qū)網(wǎng)站建設(shè)公司,為郊區(qū)等地區(qū)提供建站服務(wù)。全流程定制網(wǎng)站,專業(yè)設(shè)計,全程項目跟蹤,成都創(chuàng)新互聯(lián)專業(yè)和態(tài)度為您提供的服務(wù)這里我們繼續(xù)學(xué)習(xí)兩個比較重要的類型,就是 Object
和 Symbol
。我們主要講的是 Object,相對 Object 來說 Symbol 只是一個配角。
關(guān)于對象這個概念大家非常早就會接觸到了,其實人大概在 5 歲的時候就會產(chǎn)生對象的抽象。很多時候我們看起來好像對象是我們學(xué)編程的時候才知道有面向?qū)ο?。但是從認(rèn)知的角度來說,應(yīng)該是比我們平時對數(shù)字中的值這個類型的認(rèn)知要早的多。所以歷史的角度也一直被評價為,對象是更貼近人類的自然思維的。
剛剛說到我們從小時候就已經(jīng)產(chǎn)生了對象的概念了,那為什么說從小就有呢?Object 在英文里其實它的意思是一個非常廣泛的東西,他是任何一個物體,可以是抽象的物體,也可以是一個實際的物體。但是在我們中文里,找不到一個合適的詞,可以代表保羅萬物的詞來表達(dá) Object 的含義。所以在中文中我們就直接翻譯成 “對象”。
所以這個中文翻譯過來的詞,就造成了我們對 Object 的一定誤解。因為對象在英文中,我覺得更接近 target 這個單詞的意思。其實在臺灣就會把 Object 翻譯成 “物件”。物件這個詞在語義上確實會更貼合一些,但是物件這個詞大家也不是特別熟悉,所以它就演變成了一個技術(shù)的專用名詞。
但是不論如何,我們腦子里面應(yīng)該是有這么一個概念的,從小我們就應(yīng)該知道我們有三條一模一樣的魚,但是其實他是三個不同的對象。那為什么一模一樣的魚,他們是不同的對象呢?
我們可以這么理解哈,突然有一天其中一條魚的尾巴被咬掉了。很驚奇的發(fā)現(xiàn),另外兩條魚并不會受到影響。因此,當(dāng)我們在計算機中描述這三條魚的時候,那肯定是三組相同的數(shù)據(jù)的對象,但是是單獨儲存了三份,互相獨立的。
這種魚和魚之間的區(qū)別其實就是,他們的對象的一個特性的體現(xiàn)。一些認(rèn)知學(xué)的研究認(rèn)為我們?nèi)嗽谛r候大概 5 歲的時候就有
這樣的認(rèn)知了,其實現(xiàn)在的孩子發(fā)育的比較早,5歲已經(jīng)是一個最低的年齡了。2 ~ 3 歲的時候大家都知道這個蘋果和那個蘋果是不一樣的,這個咬一口,另外一個蘋果安然無事。
所以如果我們在計算機里面描述這三條魚的時候,我們就必須要把數(shù)據(jù)單獨存儲三份,因為是三個對象的狀態(tài),而不是我們把同一個數(shù)據(jù)存了三份,而是恰巧他們是相等而已。其實這個正是所有的面向?qū)ο缶幊痰囊粋€基礎(chǔ),也就是說,他是這條魚就是這條魚,不是這條魚就不是這條魚,不會因為對象本身的狀態(tài)改變而變得有區(qū)別。
所以我們對對象的認(rèn)知是?
任何一個對象都是唯一的,這與它本身的狀態(tài)無關(guān),狀態(tài)是由對象決定的
即使?fàn)顟B(tài)完全一致的兩個對象,也并不相等。所以有時候我們會把對象當(dāng)數(shù)據(jù)用,但是這個其實是一種語言的使用技巧而已,并不是把對象當(dāng)做對象用,比如我們傳一個 config,其實傳 config 的過程其實它并不是把對象當(dāng)對象去傳,而是我們把對象當(dāng)成一種數(shù)據(jù)載體去傳。這個時候就涉及到我們對對象類型的使用,跟語言本身的設(shè)計用途的偏差。
我們用狀態(tài)來描述對象,比如我們有一個對象 “魚”,然后他的狀態(tài)就是,它有沒有 “尾巴”、“眼睛多大”,我們都會用這些狀態(tài)值來描述一個對象。
我們的狀態(tài)的改變既是行為,狀態(tài)的改變就是魚的尾巴沒有了,被咬掉了。然后過了一段時間它又長出一條新尾巴了,然后尾巴還可以來回擺動。這些都屬于它的狀態(tài)的改變。而這些狀態(tài)的改變都是行為。
其實哲學(xué)家他們就會研究一個 Object,比如魚的唯一標(biāo)識是什么,這條魚的骨頭全部挑出來看還是不是這條魚。然后把肉都切下來,再拼起來看是不是這一條魚,這就是著名的哲學(xué)問題 “忒修斯之船”。
這個我們就不用關(guān)心,我們就說變量它是有一個唯一標(biāo)識性,這個也是對象的一個核心要素具備了。
對象就要有狀態(tài),狀態(tài)是可以被改變的,改變就是行為。這樣對象的三要素就成立了。
我們腦子里的任何一個概念和現(xiàn)實中的任何一個物品,都可以成為一個對象,只要三要素是齊備的。
首先
Class
類 和Type
類型是兩個不一樣的概念。
我們認(rèn)識對象的一個重要的方式叫做分類,我們可以用分類的方式去描述對象。比如我們研究透測一條魚之后,它與所有同類型的魚特性都是類似的,所以我們就可以把這些魚歸為一類,叫 “魚類”(Fish Class)。
其實在魚的分類上還有更大的為 “動物分類 (Animal)”,那么動物下面還有其他動物的分類,比如說羊 (Sheep)。所以說魚和羊之間他們的共性就會用 “動物” 來描述。然后我們一層一層的抽象,在 "Animal" 之上還會有 Object。
類是一個非常常見的描述對象的一種方式,比如說我們剛剛講到的生物,用對象可以把所有的生物分成界門綱目科屬種,是一個龐大的分類體系。在寫代碼的時候,分類是一個為業(yè)務(wù)服務(wù)的,我們沒有必要分的那么細(xì)。通常我們會把有共性的需要寫在代碼里的,我們就把 Animal 提出來,就不再分這個哺乳動物,還是卵生,還是脊索動物等等。
分類有兩個流派,一種是歸類
,一種是分類
。
歸類
—— 就是我們?nèi)パ芯繂蝹€對象,然后我們從里面提取共性變成類,之后我們又在類之間去提取共性,把它們變成更高的抽象類。比如我們在 “羊” 和 “魚” 中提取共性,然后把它們之間的共享再提取出來變成 “動物” 的類。對于 “歸類” 方法而言,多繼承是非常自然的事情,如 C++ 中的菱形繼承,三角形繼承等。分類
—— 則是把世界萬物都抽象為一個基類 Object,然后定義這個 Object 中有什么。采用分類思想的計算機語言,則是單繼承結(jié)構(gòu)。并且會有一個基類 Object。JavaScript 這個語言比較接近 “分類” 這個思想,但是它也不完全是分類的思想,因為它是一個多范式的面向?qū)ο笳Z言。
接下來我們講一講 JavaScript 描述對象的方式。
其實分類 Class Based 的 Object 并不是一個唯一的認(rèn)識對象的方法,我們還有一個更接近人類自然認(rèn)知的。分類的能力可能至少要到小學(xué)才有的。但是我們認(rèn)識對象之后,幾乎是馬上就可以得到另外一種描述對象的方式。那就是 “原型”。
原型其實用 “照貓畫虎” 來理解 ,其實照貓畫虎就是用的一種原型方法。因為貓和虎很像,所以我們只需要把它們直接的有區(qū)別的地方分出來就可以了。
比如說我們現(xiàn)在想研究魚,那么找一種典型的魚,比如找一條具體的鯉魚,然后我們把這條鯉魚所有的特征都加到魚類的原型上。其他的魚只要有對象,我們就根據(jù)魚的原型進(jìn)行修改。比如說鯰魚比鯉魚更能吃,它是吃肉的,而且身上還是滑滑的,所以我們就可以在鯉魚的原型基礎(chǔ)上把這些特征加上,這樣我們就能描述出鯰魚了。
那么在羊類里面,我們也選中一只小綿羊來做我們的基礎(chǔ)原型。然后如果我們找到一只山羊,我們分析出它的特性是多胡子,腳是彎點,又長又硬又能爬山,那么我們就在小綿羊的原型上加上這些特性,那我們就描述了一只山羊了。
那么在上級的 “動物” 中我們也選一只典型的動物,比如說老虎,有四個蹄,但是不一定所有動物都有4個蹄子,不過原型選擇相對來說它是比較自由的。比如說我們選擇蛇作為動物的原型的話,那么我們在描述魚的時候就特別費勁了,描述貓的時候就更費勁了。
原型里面也會有一個最終版的原型叫 Object Prototype
,這個就是所有物品的典型的物品,也可以說是我們所有對象的老祖宗。我們描述任何對象都是從它與描述對象的區(qū)別來進(jìn)行描述的。
然后在 Object Prototype
之上一般來說是不會再有原型了,但是有一些語言里面會允許有一種 Nihilo
原型。Nihilo 的意思就是虛無空虛,這個是語言中立的講法。如果我們用 JavaScript 的具體的設(shè)施來描述,那這個 Nihilo
原型就是 null
,這個大家就很容易理解了,我們很容易就可以簡歷一個 null
對象的原型。
小總結(jié):
- 我們這種原型是更接近人類原始認(rèn)知的描述對象的方法
- 所以面向?qū)ο蟮母鞣N方法其實并沒有絕對的對錯,只存在在不同場景下不同的代價
- 原型的認(rèn)知成本低,選錯的成本也比較低,所以原型適合一些不是那么清晰和描述上比較自由的場景
- 而分類(Class)更適合用在一些比較嚴(yán)謹(jǐn)?shù)膱鼍埃?Class 有一個優(yōu)點,它天然的跟類型系統(tǒng)有一定的整合的,所以很多的語言就會選擇把 Class 的繼承關(guān)系整合進(jìn)類型系統(tǒng)的繼承關(guān)系當(dāng)中
我們?nèi)绻枰帉懸粋€ “狗 咬 人” 的 Class,我們需要怎么去設(shè)計呢?
如果我們按照一個比較樸素的方法,我們就會去定義一個 Dog
Class,然后里面給予這個 Class 一個 bite
的方法。
class Dog { bite(Human) { // ...... } }復(fù)制代碼
這樣的一段代碼是跟我們的題目是一模一樣的,但是這個抽象是一個錯誤的抽象。因為這個違背了面向?qū)ο蟮幕咎卣鳎还芪覀兪窃趺丛O(shè)計,只要這個 bite
發(fā)生在狗身上就是錯誤的。
為什么?
因為我們前面講到了面向?qū)ο蟮娜兀瑢ο蟮臓顟B(tài)必須是對象本身的行為才能改變的。那么如果我們在狗的 Class 中寫 bite
這個動作,但是改變的狀態(tài)是 “人”,最為狗咬了人之后,只會對人造成傷害。所以在這個行為中 “人” 的狀態(tài)是發(fā)生變化的,那么如果行為是在狗的 Class 中就違反了面向?qū)ο蟮奶卣髁恕?/p>
當(dāng)然如果是狗吃人,那我們勉強是可以成立的,因為狗吃了人狗就飽了,那對狗的狀態(tài)是有發(fā)生改變的。但是狗咬人,我們基本可以認(rèn)為這個行為對狗的狀態(tài)是沒有發(fā)生任何改變的。
所以我們應(yīng)該在 “人” 的 Class 中設(shè)計一個行為。那么有些同學(xué)就會問,我們是應(yīng)該在人的身上加入一個 biteBy
行為嗎?就是人被咬的一個行為?似乎也不對,因為人 Class 里面的行為應(yīng)該是用于改變?nèi)说臓顟B(tài)的,那這個行為的命名應(yīng)該是怎么樣的呢?
這里更加合理的行為應(yīng)該是 hurt
表示被傷害了,然后傳入這個行為的參數(shù)就是受到的傷害程度 damage
。因為這里人只關(guān)心它受到的傷害有多少就可以了,他是不需要關(guān)心是狗咬的還是什么咬的。
class Human { hurt(damage) { //...... } }復(fù)制代碼
狗咬人在實際開發(fā)場景中,是一個業(yè)務(wù)邏輯,我們只需要設(shè)計改變?nèi)?Human
對象內(nèi)部的狀態(tài)的行為,所以它正確的命名應(yīng)該是 hurt
。這里的 damage
,可以從狗 Class 中咬 bite
, 的行為方法中計算或者生成出來的一個對象,但是如果我們直接傳狗 Dog
的對象進(jìn)來的話,肯定是不符合我們對對象的抽象原則的。
最終我們的代碼實現(xiàn)邏輯如下:
class Human { constructor(name = '人') { this.name = name; this.hp = 100; } hurt(damage) { this.hp -= damage; console.log(`${this.name} 受到了 ${damage} 點傷害,剩余生命中為 ${this.hp}`); } }class Dog { constructor(name = '狗') { this.name = name; this.attackPower = 10; // 攻擊力 } bite() { return this.attackPower; } }let human = new Human('三鉆');let dog = new Dog(); human.hurt(dog.bite()); // 輸出:三鉆 受到了 10 點傷害,剩余生命中為 90復(fù)制代碼
設(shè)計對象的原則:
- 我們不應(yīng)該受到語言描述的干擾(特別是業(yè)務(wù)需求的干擾)
- 在設(shè)計對象的狀態(tài)和行為時,我們總是遵循 “行為改變狀態(tài)” 的原則
- 違背了這個原則,整個對象的內(nèi)聚性就沒有了,這個對架構(gòu)上會造成巨大的破壞
看完了這篇文章,相信你對JavaScript 對象是什么有了一定的了解,想了解更多相關(guān)知識,歡迎關(guān)注創(chuàng)新互聯(lián)-成都網(wǎng)站建設(shè)公司行業(yè)資訊頻道,感謝各位的閱讀!