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

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

[值與類型]關(guān)于編程中的“量”和“值”——JavaScript視角

2020-10-03 15:52 作者:useStrict  | 我要投稿

本文全文依cc0公開授權(quán)。?

https://creativecommons.org/choose/zero/?lang=zh


很多人,包括很多有相當(dāng)經(jīng)驗(yàn)的開發(fā)者/程序員,很容易混淆或忽略量和值的概念和區(qū)別,而這種混淆有時(shí),尤其是在某些編程語(yǔ)言中,會(huì)造成一些微妙的誤會(huì),因此恰當(dāng)?shù)脜^(qū)分這兩者是有意義的。


實(shí)現(xiàn)/物理/機(jī)器層面的“量”和“值”

這里的“機(jī)器層面”并不指實(shí)際的某種電子計(jì)算機(jī),而是指針對(duì)現(xiàn)在的計(jì)算機(jī)的抽象模型。實(shí)際上,我們?cè)趯?shí)踐中所討論的“機(jī)器層面”,經(jīng)常是“C編譯器和libc眼中的”機(jī)器層面,也就是C編譯器為程序員提供的對(duì)機(jī)器的抽象。

與圖靈機(jī)相似,這種模型中都存在一條紙帶,這條紙帶被劃分為一個(gè)一個(gè)的格子,而每個(gè)格子可以被寫入數(shù)字0或1。但與圖靈機(jī)不同,這條紙帶是被編址的并能夠被隨機(jī)訪問(wèn),也就是說(shuō)給定一個(gè)地址,“讀寫頭”可以立即轉(zhuǎn)到地址所指向的格子,而這條紙帶被叫做內(nèi)存。當(dāng)然,這都是小事。

另外,如果你使用過(guò)lisp機(jī)的話,那么是不是lisp機(jī)的機(jī)器層面會(huì)與C的機(jī)器層面大不相同呢?

在這樣的機(jī)器層面上,“量”指的是內(nèi)存的“格子”,而“值”指的是“格子中的內(nèi)容”:量是容器,值是內(nèi)容,這兩者的區(qū)分雖然相當(dāng)顯而易見,但也相當(dāng)容易被忽略。畢竟把“一杯水”區(qū)分為“一杯”和“水”似乎并沒有太大必要——雖然你大概從來(lái)沒有喝過(guò)玻璃。


但語(yǔ)言層面和機(jī)器層面是不同的

這實(shí)際上本來(lái)應(yīng)該是一件挺顯然的事情:編程語(yǔ)言提供了一系列抽象,不是為了讓程序員試圖去窺探和接觸底層邏輯的。但是C和C++卻似乎很喜歡培養(yǎng)黑客,這兩門語(yǔ)言中的很多概念都與底層實(shí)現(xiàn)有著清晰的對(duì)應(yīng),這在某種意義上是好的,但是這也讓很多人養(yǎng)成了某些微妙的習(xí)慣,然而這種清晰的對(duì)應(yīng)卻不是何時(shí)何地都存在的。

把編譯器視作魔法,雖然很多時(shí)候它并不是那么得魔法,至少能讓人輕松很多。當(dāng)然,也不是任何時(shí)候都必須把編譯器看作魔法,不然就沒有人再去維護(hù)編譯器了。

簡(jiǎn)單得說(shuō),標(biāo)識(shí)符本身即是量,而標(biāo)識(shí)符所指向的東西,無(wú)論它指向的是什么,是如何指向的,這個(gè)被指向的東西是值。與其說(shuō)量是容器而值是內(nèi)容,不如說(shuō)量是能指而值是所指,量是名稱而值是實(shí)體。

identifier和signifier的確很像呢...畢竟形式語(yǔ)言也是語(yǔ)言,語(yǔ)言學(xué)理論當(dāng)然也對(duì)形式語(yǔ)言有效。

比如在`let?a = 1`中,a是一個(gè)量,量a指向值1。

這里的“指向”是抽象意義上,或者說(shuō)語(yǔ)言意義上的指向。

而在`a = a + 1`中,則是計(jì)算(a+1)的值,令a重新指向它:“令a指向a+1”,而不是“令a加1”,才是這一語(yǔ)句在幾乎所有語(yǔ)言中的確切語(yǔ)義。

注意,此處只談?wù)Z義而不談實(shí)現(xiàn),實(shí)現(xiàn)是編譯器才需要關(guān)心的。

至少在JavaScript中,這并不是像C一樣的,a對(duì)應(yīng)了某一段內(nèi)存,而這一段內(nèi)存中的數(shù)字是1。所以請(qǐng)把JavaScript代碼看作是直接運(yùn)行在JavaScript引擎這一魔法之上的。

也是存在著某些語(yǔ)句具有“令a加1”這一語(yǔ)義的:at&t語(yǔ)法的`addq $1, %rax`便具“令rax加1”的語(yǔ)義。

機(jī)器/計(jì)算模型層面只允許0和1兩個(gè)值,但絕大多數(shù)語(yǔ)言允許的值比這些要多得多,包括0, 1, 2, 3,'a', 'b', c', d'以及'abcd',也包括自定義值,比如[1, 2, 3]和{a: 1, b: 2, c: 3},這些值被編譯器/引擎通過(guò)某種簡(jiǎn)單的魔法映射到了底層實(shí)現(xiàn),但是我們并不真的需要關(guān)心這一實(shí)現(xiàn)。


JavaScript視角

JavaScript引擎允許7種"原始類型"的值,外加僅此一種的非原始類型,Object。

雖然說(shuō)實(shí)際上某些Object值,就是說(shuō)Array和Function,對(duì)引擎有某種特權(quán),但總得來(lái)說(shuō),它們依然是Object。

注意,是7+1種“值”,而不是7+1種“量”。

為什么說(shuō)是7+1種值呢,比如說(shuō)

let a

定義了一個(gè)變量,而

a = 1

使得a指向了值1,或者

a = {a: 1}

使得a指向了值{a: 1}

其中1是number類型的值,而{a: 1}則是Object類型的值。

那么我們看到,a從來(lái)沒有關(guān)心過(guò)這些值屬于那些分類,而這些值卻天生帶有分類。所以,這些分類是為了劃分值而產(chǎn)生的,與量并沒有關(guān)系。

像大多數(shù)語(yǔ)言一樣,JavaScript中的值大都是不可變的,比如1永遠(yuǎn)都是1,某個(gè)量可能會(huì)從指向1變成指向2,但1永遠(yuǎn)不會(huì)變。在機(jī)器層面上,內(nèi)存中的某一位可能由0變?yōu)?,但是0這一數(shù)字本身永遠(yuǎn)不會(huì)是1。值是不變的,會(huì)變的只有指向,或者說(shuō)量和值的對(duì)應(yīng)關(guān)系。

不過(guò)JavaScript中有一類值卻是會(huì)變的,這就是被排除在7類primitive value之外的Object。

但是為什么要有一種會(huì)變的值呢?

比如說(shuō)你種下了一棵種子,把它命名為小花,過(guò)了幾天小花長(zhǎng)成了幼苗,你非常開心,無(wú)論是那顆種子還是這株幼苗,小花一直都是那個(gè)小花,但是它已經(jīng)不是你種下它的時(shí)候的樣子的。

Object就是這樣一顆能夠發(fā)芽的種子。

這種可變性使得Object能夠被用來(lái)做很多事情,不過(guò)也容易產(chǎn)生一些不太符合直覺的行為。

值的類型

我們知道值天然具有類型,比如1就是一個(gè)數(shù)字,而a就是一個(gè)字母。從數(shù)學(xué)上,我們可以把具有某一類性質(zhì)的值歸類于一個(gè)集合,這樣的集合就叫做類型。

當(dāng)然,值并不必須按照7種基本類型那樣劃分,這樣的劃分實(shí)際上是為了實(shí)現(xiàn)方便:因?yàn)椴煌愋偷闹敌枰煌膶?shí)現(xiàn),引擎將實(shí)現(xiàn)相同的值歸結(jié)為了同種類型:但是類型本身并不必然需要與實(shí)現(xiàn)掛鉤。

比如“0到255的整數(shù)”可以是一種類型,{0, 1, 2, 4}也可以是一種類型,換言之,只要集合論允許,有限或無(wú)限的值的任意一種集合都可以是一種類型,比如空集在很多種語(yǔ)言中都對(duì)應(yīng)void類型。

量的類型:靜態(tài)類型系統(tǒng)與動(dòng)態(tài)類型系統(tǒng)

量本身并不需要具有類型,因?yàn)榱坎恍枰P(guān)心其中的值是什么。但是很多語(yǔ)言中量同樣是具有類型的,而這種類型實(shí)際上是一種約束:被聲明為某個(gè)類型的量只能指向某個(gè)類型的值,如果這條規(guī)則被違反,那么編譯器被期望能夠產(chǎn)生編譯時(shí)錯(cuò)誤。

之所以需要這么做,是因?yàn)榇蠖鄶?shù)編譯型語(yǔ)言必須在編譯時(shí)確定值對(duì)應(yīng)的實(shí)現(xiàn),并且無(wú)法在運(yùn)行時(shí)確定值的類型。如果某個(gè)量被允許指向?qū)崿F(xiàn)不同的值,那么編譯器就必須用某種方式為其選擇實(shí)現(xiàn)。能夠在編譯時(shí)選擇實(shí)現(xiàn)的特性叫做編譯時(shí)多態(tài),著名的標(biāo)準(zhǔn)模板庫(kù)(STL)所使用的“模板”就是編譯時(shí)多態(tài)的一種實(shí)現(xiàn)。當(dāng)然也有運(yùn)行時(shí)多態(tài),C++的虛函數(shù)就是一種運(yùn)行時(shí)多態(tài)的實(shí)現(xiàn)。

不過(guò)雖然具有多態(tài)和運(yùn)行時(shí)類型標(biāo)注,C++的類型系統(tǒng)依然是靜態(tài)的。

與之相反的,JavaScript使用了動(dòng)態(tài)類型系統(tǒng),因而不對(duì)量能夠指向的值的類型做約束,相對(duì)的,JavaScript在運(yùn)行時(shí)進(jìn)行值類型檢查,如果值的類型不符,則會(huì)產(chǎn)生運(yùn)行時(shí)錯(cuò)誤:事實(shí)上,JavaScript引擎從來(lái)不會(huì)放過(guò)任何一個(gè)運(yùn)行時(shí)類型錯(cuò)誤,畢竟對(duì)于這種錯(cuò)誤,引擎根本不知道如何執(zhí)行下去,所以就只好報(bào)錯(cuò)了:和某個(gè)著名web腳本語(yǔ)言相比,這反而是一件好事。

動(dòng)態(tài)類型系統(tǒng)更為靈活,但也犧牲了在編譯時(shí)提前進(jìn)行類型檢查的能力:這就使得某些編譯時(shí)錯(cuò)誤成了運(yùn)行時(shí)錯(cuò)誤。

不過(guò)畢竟JavaScript也并不存在編譯時(shí)。

厘清量與值的區(qū)別,我們就能更好得理解JavaScript以及其他的動(dòng)態(tài)類型語(yǔ)言背后的邏輯,希望這篇文章能夠給大家?guī)?lái)更多的一時(shí)爽和更少的火葬場(chǎng)。


===============================================


附加題:'1'+1='11'是誰(shuí)的錯(cuò)?

* 靜態(tài)類型語(yǔ)言是如何應(yīng)對(duì)這種情況的?

* 如果讓你來(lái)寫ECMA262,你會(huì)如何避免這種錯(cuò)誤?

* 某個(gè)著名web腳本語(yǔ)言沒有將operator+重載為字符串拼接運(yùn)算符,對(duì)此你怎么看?

[值與類型]關(guān)于編程中的“量”和“值”——JavaScript視角的評(píng)論 (共 條)

分享到微博請(qǐng)遵守國(guó)家法律
朝阳市| 九龙县| 嘉义市| 商水县| 泸溪县| 尉氏县| 静安区| 平泉县| 延边| 措美县| 龙川县| 定安县| 宜黄县| 密山市| 伊吾县| 金川县| 南川市| 普兰店市| 陇西县| 珠海市| 鞍山市| 班戈县| 开化县| 房产| 礼泉县| 从江县| 镇巴县| 余姚市| 阆中市| 汾阳市| 贵定县| 额尔古纳市| 鸡西市| 五原县| 托克逊县| 高邮市| 柳江县| 宁国市| 山阳县| 宜兴市| 泸定县|