溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點(diǎn)擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

javascript是基于對象的語言嗎

發(fā)布時(shí)間:2021-07-23 17:48:34 來源:億速云 閱讀:116 作者:chen 欄目:web開發(fā)

這篇文章主要講解了“javascript是基于對象的語言嗎”,文中的講解內(nèi)容簡單清晰,易于學(xué)習(xí)與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學(xué)習(xí)“javascript是基于對象的語言嗎”吧!

javascript是面向?qū)ο蟮?,js每個(gè)內(nèi)建對象都是從object派生出來的,這樣就有繼承,多態(tài)和重構(gòu)三個(gè)面向?qū)ο蟮奶匦裕词宫F(xiàn)在js是基于prototype的偽繼承,但是總體思想是一個(gè)面向?qū)ο蟮恼Z言。

本教程操作環(huán)境:windows7系統(tǒng)、javascript1.8.5版、Dell G3電腦。

與其它的語言相比,JavaScript中的“對象”總是顯得不是那么合群。一些新人在學(xué)習(xí)JavaScript面向?qū)ο髸r(shí),往往也會(huì)有疑惑:為什么JavaScript(直到ES6)有對象的概念,但是卻沒有像其他的語言那樣,有類的概念呢?為什么在JavaScript對象里可以自由添加屬性,而其他的語言卻不能呢?

甚至一些爭論中,有人強(qiáng)調(diào),JavaScript并非“面向?qū)ο蟮恼Z言”,而是“基于對象的語言”,這個(gè)說法一度流傳甚廣,而事實(shí)上,我至今遇到的持有這一說法的人中,無一能夠回答“如何定義面向?qū)ο蠛突趯ο蟆边@個(gè)問題。

實(shí)際上,基于對象和面向?qū)ο髢蓚€(gè)形容詞都出現(xiàn)在了JavaScript標(biāo)準(zhǔn)的各個(gè)版本當(dāng)中。我們可以先看看JavaScript標(biāo)準(zhǔn)對基于對象的定義,這個(gè)定義的具體內(nèi)容是:“語言和宿主的基礎(chǔ)設(shè)施由對象來提供,并且ECMAScript程序即是一系列互相通訊的對象集合”。這里的意思根本不是表達(dá)弱化的面向?qū)ο蟮囊馑?,反而是表達(dá)對象對于語言的重要性。

那么,在本篇文章中,我會(huì)嘗試讓你去理解面向?qū)ο蠛蚃avaScript中的面向?qū)ο缶烤故鞘裁础?/p>

什么是對象?

我們先來說說什么是對象,因?yàn)榉g的原因,中文語境下我們很難理解“對象”的真正含義。事實(shí)上,Object(對象)在英文中,是一切事物的總稱,這和面向?qū)ο缶幊痰某橄笏季S有互通之處。中文的“對象”卻沒有這樣的普適性,我們在學(xué)習(xí)編程的過程中,更多是把它當(dāng)作一個(gè)專業(yè)名詞來理解。

但不論如何,我們應(yīng)該認(rèn)識(shí)到,對象并不是計(jì)算機(jī)領(lǐng)域憑空造出來的概念,它是順著人類思維模式產(chǎn)生的一種抽象(于是面向?qū)ο缶幊桃脖徽J(rèn)為是:更接近人類思維模式的一種編程范式)。

那么,我們先來看看在人類思維模式下,對象究竟是什么。

對象這一概念在人類的幼兒期形成,這遠(yuǎn)遠(yuǎn)早于我們編程邏輯中常用的值、過程等概念。在幼年期,我們總是先認(rèn)識(shí)到某一個(gè)蘋果能吃(這里的某一個(gè)蘋果就是一個(gè)對象),繼而認(rèn)識(shí)到所有的蘋果都可以吃(這里的所有蘋果,就是一個(gè)類),再到后來我們才能意識(shí)到三個(gè)蘋果和三個(gè)梨之間的聯(lián)系,進(jìn)而產(chǎn)生數(shù)字“3”(值)的概念。

在《面向?qū)ο蠓治雠c設(shè)計(jì)》這本書中,Grady Booch替我們做了總結(jié),他認(rèn)為,從人類的認(rèn)知角度來說,對象應(yīng)該是下列事物之一:

  • 一個(gè)可以觸摸或者可以看見的東西;

  • 人的智力可以理解的東西;

  • 可以指導(dǎo)思考或行動(dòng)(進(jìn)行想象或施加動(dòng)作)的東西。

有了對象的自然定義后,我們就可以描述編程語言中的對象了。在不同的編程語言中,設(shè)計(jì)者也利用各種不同的語言特性來抽象描述對象,最為成功的流派是使用“類”的方式來描述對象,這誕生了諸如 C++、Java等流行的編程語言。而 JavaScript 早年卻選擇了一個(gè)更為冷門的方式:原型(關(guān)于原型,我在下一篇文章會(huì)重點(diǎn)介紹,這里你留個(gè)印象就可以了)。這是我在前面說它不合群的原因之一。

然而很不幸,因?yàn)橐恍┕菊卧?,JavaScript推出之時(shí)受管理層之命被要求模仿Java,所以,JavaScript創(chuàng)始人Brendan Eich在“原型運(yùn)行時(shí)”的基礎(chǔ)上引入了new、this等語言特性,使之“看起來更像Java”。

在 ES6 出現(xiàn)之前,大量 JavaScript 程序員試圖在原型體系的基礎(chǔ)上,把JavaScript變得更像是基于類的編程,進(jìn)而產(chǎn)生了很多所謂的“框架”,比如PrototypeJS、Dojo。事實(shí)上,它們成為了某種JavaScript的古怪方言,甚至產(chǎn)生了一系列互不相容的社群,顯然這樣做的收益遠(yuǎn)遠(yuǎn)小于損失。

如果我們從運(yùn)行時(shí)角度來談?wù)搶ο螅褪窃谟懻揓avaScript實(shí)際運(yùn)行中的模型,這是由于任何代碼執(zhí)行都必定繞不開運(yùn)行時(shí)的對象模型,不過,幸運(yùn)的是,從運(yùn)行時(shí)的角度看,可以不必受到這些“基于類的設(shè)施”的困擾,這是因?yàn)槿魏握Z言運(yùn)行時(shí)類的概念都是被弱化的。

首先我們來了解一下JavaScript是如何設(shè)計(jì)對象模型的。

JavaScript 對象的特征

在我看來,不論我們使用什么樣的編程語言,我們都先應(yīng)該去理解對象的本質(zhì)特征(參考Grandy Booch《面向?qū)ο蠓治雠c設(shè)計(jì)》)。總結(jié)來看,對象有如下幾個(gè)特點(diǎn)。

  • 對象具有唯一標(biāo)識(shí)性:即使完全相同的兩個(gè)對象,也并非同一個(gè)對象。

  • 對象有狀態(tài):對象具有狀態(tài),同一對象可能處于不同狀態(tài)下。

  • 對象具有行為:即對象的狀態(tài)可能因?yàn)樗男袨楫a(chǎn)生變遷。

我們先來看第一個(gè)特征,對象具有唯一標(biāo)識(shí)性。一般而言,各種語言的對象唯一標(biāo)識(shí)性都是用內(nèi)存地址來體現(xiàn)的,所以,JavaScript程序員都知道,任何不同的JavaScript對象其實(shí)是互不相等,我們可以看下面的代碼,o1和o2初看是兩個(gè)一模一樣的對象,但是打印出來的結(jié)果卻是false。

var o1 = { a: 1 };
var o2 = { a: 1 };
console.log(o1 == o2); // false

關(guān)于對象的第二個(gè)和第三個(gè)特征“狀態(tài)和行為”,不同語言會(huì)使用不同的術(shù)語來抽象描述它們,比如C++中稱它們?yōu)椤俺蓡T變量”和“成員函數(shù)”,Java中則稱它們?yōu)椤皩傩浴焙汀胺椒ā薄?/p>

在 JavaScript中,將狀態(tài)和行為統(tǒng)一抽象為“屬性”,考慮到 JavaScript 中將函數(shù)設(shè)計(jì)成一種特殊對象(關(guān)于這點(diǎn),我會(huì)在后文中詳細(xì)講解,此處先不用細(xì)究),所以 JavaScript中的行為和狀態(tài)都能用屬性來抽象。

下面這段代碼其實(shí)就展示了普通屬性和函數(shù)作為屬性的一個(gè)例子,其中o是對象,d是一個(gè)屬性,而函數(shù)f也是一個(gè)屬性,盡管寫法不太相同,但是對JavaScript來說,d和f就是兩個(gè)普通屬性。

var o = {     
d: 1,
    f() {
            console.log(this.d);
            }    
     };

所以,總結(jié)一句話來看,在JavaScript中,對象的狀態(tài)和行為其實(shí)都被抽象為了屬性。如果你用過Java,一定不要覺得奇怪,盡管設(shè)計(jì)思路有一定差別,但是二者都很好地表現(xiàn)了對象的基本特征:標(biāo)識(shí)性、狀態(tài)和行為。

在實(shí)現(xiàn)了對象基本特征的基礎(chǔ)上, 我認(rèn)為,JavaScript中對象獨(dú)有的特色是:對象具有高度的動(dòng)態(tài)性,這是因?yàn)镴avaScript賦予了使用者在運(yùn)行時(shí)為對象添改狀態(tài)和行為的能力。

我來舉個(gè)例子,比如,JavaScript 允許運(yùn)行時(shí)向?qū)ο筇砑訉傩裕@就跟絕大多數(shù)基于類的、靜態(tài)的對象設(shè)計(jì)完全不同。如果你用過Java或者其它別的語言,肯定會(huì)產(chǎn)生跟我一樣的感受。

下面這段代碼就展示了運(yùn)行時(shí)如何向一個(gè)對象添加屬性,一開始我定義了一個(gè)對象o,定義完成之后,再添加它的屬性b,這樣操作,是完全沒問題的。這一點(diǎn)你要理解。

var o = { a: 1 };
o.b = 2;
console.log(o.a, o.b); //1 2

為了提高抽象能力,JavaScript的屬性被設(shè)計(jì)成比別的語言更加復(fù)雜的形式,它提供了數(shù)據(jù)屬性和訪問器屬性(getter/setter)兩類。

JavaScript對象的兩類屬性

對JavaScript來說,屬性并非只是簡單的名稱和值,JavaScript用一組特征(attribute)來描述屬性(property)。

先來說第一類屬性,數(shù)據(jù)屬性。它比較接近于其它語言的屬性概念。數(shù)據(jù)屬性具有四個(gè)特征。

  • value:就是屬性的值。

  • writable:決定屬性能否被賦值。

  • enumerable:決定for in能否枚舉該屬性。

  • configurable:決定該屬性能否被刪除或者改變特征值。

在大多數(shù)情況下,我們只關(guān)心數(shù)據(jù)屬性的值即可。

第二類屬性是訪問器(getter/setter)屬性,它也有四個(gè)特征。

  • getter:函數(shù)或undefined,在取屬性值時(shí)被調(diào)用。

  • setter:函數(shù)或undefined,在設(shè)置屬性值時(shí)被調(diào)用。

  • enumerable:決定for in能否枚舉該屬性。

  • configurable:決定該屬性能否被刪除或者改變特征值。

訪問器屬性使得屬性在讀和寫時(shí)執(zhí)行代碼,它允許使用者寫入和讀出屬性時(shí)得到完全不同的值,它可以視為一種函數(shù)的語法糖。

我們通常用于定義屬性的代碼會(huì)產(chǎn)生數(shù)據(jù)屬性,其中的writable、enumerable、configurable都默認(rèn)為true。我們可以使用內(nèi)置函數(shù) Object.getOwnPropertyDescripter來查看,如以下代碼所示:

var o = { a: 1 };
o.b = 2;//a和b皆為數(shù)據(jù)屬性
Object.getOwnPropertyDescriptor(o,\u0026quot;a\u0026quot;) // {value: 1, writable: true, enumerable: true, configurable: true}
Object.getOwnPropertyDescriptor(o,\u0026quot;b\u0026quot;) // {value: 2, writable: true, enumerable: true, configurable: true}

我們在這里使用了兩種語法來定義屬性,定義完屬性后,我們用JavaScript的API來查看這個(gè)屬性,我們可以發(fā)現(xiàn),這樣定義出來的屬性都是數(shù)據(jù)屬性,writeable、enumerable、configurable都是默認(rèn)值為true。

如果我們要想改變屬性的特征,或者定義訪問器屬性,可以使用 Object.defineProperty,示例如下:

var o = { a: 1 };
Object.defineProperty(o, \u0026quot;b\u0026quot;, {value: 2, writable: false, enumerable: false, configurable: true});//a和b都是數(shù)據(jù)屬性,但特征值變化了
Object.getOwnPropertyDescriptor(o,\u0026quot;a\u0026quot;); // {value: 1, writable: true, enumerable: true, configurable: true}
Object.getOwnPropertyDescriptor(o,\u0026quot;b\u0026quot;); // {value: 2, writable: false, enumerable: false, configurable: true}o.b = 3;console.log(o.b); // 2

這里我們使用了Object.defineProperty來定義屬性,這樣定義屬性可以改變屬性的writable和enumerable,我們同樣用Object.getOwnPropertyDescriptor來查看,發(fā)現(xiàn)確實(shí)改變了writable和enumerable特征。因?yàn)閣ritable特征為false,所以我們重新對b賦值,b的值不會(huì)發(fā)生變化。

在創(chuàng)建對象時(shí),也可以使用 get 和 set 關(guān)鍵字來創(chuàng)建訪問器屬性,代碼如下所示:

var o = { 
get a() { 
return 1 
} 
};
console.log(o.a); // 1

訪問器屬性跟數(shù)據(jù)屬性不同,每次訪問屬性都會(huì)執(zhí)行g(shù)etter或者setter函數(shù)。這里我們的getter函數(shù)返回了1,所以o.a每次都得到1。

這樣,我們就理解了,實(shí)際上JavaScript 對象的運(yùn)行時(shí)是一個(gè)“屬性的集合”,屬性以字符串或者Symbol為key,以數(shù)據(jù)屬性特征值或者訪問器屬性特征值為value。對象是一個(gè)屬性的索引結(jié)構(gòu)(索引結(jié)構(gòu)是一類常見的數(shù)據(jù)結(jié)構(gòu),我們可以把它理解為一個(gè)能夠以比較快的速度用key來查找value的字典)。我們以上面的對象o為例,你可以想象一下“a”是key。

這里{writable:true,value:1,configurable:true,enumerable:true}是value。我們在前面的類型課程中,已經(jīng)介紹了Symbol類型,能夠以Symbol為屬性名,這是JavaScript對象的一個(gè)特色。

講到了這里,如果你理解了對象的特征,也就不難理解我開篇提出來的問題。

你甚至可以理解為什么會(huì)有“JavaScript不是面向?qū)ο蟆边@樣的說法:JavaScript的對象設(shè)計(jì)跟目前主流基于類的面向?qū)ο蟛町惙浅4蟆6聦?shí)上,這樣的對象系統(tǒng)設(shè)計(jì)雖然特別,但是JavaScript提供了完全運(yùn)行時(shí)的對象系統(tǒng),這使得它可以模仿多數(shù)面向?qū)ο缶幊谭妒剑ㄏ乱还?jié)課我們會(huì)給你介紹JavaScript中兩種面向?qū)ο缶幊痰姆妒剑夯陬惡突谠停?,所以它也是正統(tǒng)的面向?qū)ο笳Z言。

JavaScript語言標(biāo)準(zhǔn)也已經(jīng)明確說明,JavaScript是一門面向?qū)ο蟮恼Z言,我想標(biāo)準(zhǔn)中能這樣說正因?yàn)镴avaScript的高度動(dòng)態(tài)性的對象系統(tǒng)。

所以,我們應(yīng)該在理解其設(shè)計(jì)思想的基礎(chǔ)上充分挖掘它的能力,而不是機(jī)械地模仿其它語言。

結(jié)語

要想理解JavaScript對象,必須清空我們腦子里“基于類的面向?qū)ο蟆毕嚓P(guān)的知識(shí),回到人類對對象的樸素認(rèn)知和面向?qū)ο蟮恼Z言無關(guān)基礎(chǔ)理論,我們就能夠理解JavaScript面向?qū)ο笤O(shè)計(jì)的思路。

在這篇文章中,我從對象的基本理論出發(fā),和你理清了關(guān)于對象的一些基本概念,分析了JavaScript對象的設(shè)計(jì)思路。接下來又從運(yùn)行時(shí)的角度,介紹了JavaScript對象的具體設(shè)計(jì):具有高度動(dòng)態(tài)性的屬性集合。

很多人在思考JavaScript對象時(shí),會(huì)帶著已有的“對象”觀來看問題,最后的結(jié)果當(dāng)然就是“剪不斷理還亂”了。

感謝各位的閱讀,以上就是“javascript是基于對象的語言嗎”的內(nèi)容了,經(jīng)過本文的學(xué)習(xí)后,相信大家對javascript是基于對象的語言嗎這一問題有了更深刻的體會(huì),具體使用情況還需要大家實(shí)踐驗(yàn)證。這里是億速云,小編將為大家推送更多相關(guān)知識(shí)點(diǎn)的文章,歡迎關(guān)注!

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI