理解 JavaScript 的記憶體與變數儲存

理解 JavaScript 的記憶體與變數儲存

在前端領域,因為大部分在跟UI打交道,記憶體管理是最容易被忽略的部分。如果不懂記憶體,就看不清很多問題的本質,也難以寫出更合格的程式碼,本次帶大家走進記憶體的世界。

JS神奇的Number

案例一:金額的計算與傳遞

18。9

*

100

=

1889。9999999999998

複製程式碼

案例二:違背的數學定律

0。1

+

0。2

===

0。3

// false

function

a, b, c

{

return

a + b + c === a + ( b + c )

})(

0。1

0。2

0。3

// false

複製程式碼

案例三:無限迴圈的加法

function

num

{

while

true

) {

if

(++num %

13

===

0

) {

return

num

}

}

})(

2

**

53

複製程式碼

案例四:JSON.parse

JSON

。parse(

‘{“a”:180143985094813214124}’

//{a: 180143985094813220000}

複製程式碼

透過上面的四個案例我們可以看出,數字在計算機中運算往往會給人帶來一些“驚喜”,要想防止這些意想不到的結果,我們首先要了解

Number在Javascript中到底是怎麼儲存的?

儲存數字

計算機是用二進位制來儲存資料的,所以數字也需要轉換成相應二進位制:000 或者 111 的不同組合序列。

二進位制如何轉換

如何將一個數字轉換成二進位制,這裡舉個例子說明一下:

把十進位制小數 106。6953125106。6953125106。6953125 轉換成二進位制

遇到小數轉換時,需要把整數和小數兩部分分別進行處理,整數 106106106 除以 222 直到商是 000 為止,取每次除 222 得到的餘數結果

106

/

2

=

53

……

0

53

/

2

=

26

……

1

26

/

2

=

13

……

0

13

/

2

=

6

……

1

6

/

2

=

3

……

0

3

/

2

=

1

……

1

1

/

2

=

0

……

1

結果為得到的餘數按照從右往左排列

1101010

複製程式碼

小數 0。69531250。69531250。6953125 乘以 222 直到不存在小數位為止,並計下每次乘後的整數位結果,

0。6953125

x

2

=

1。390625

……

1

0。390625

x

2

=

0。78125

……

0

0。78125

x

2

=

1。5625

……

1

0。5625

x

2

=

1。125

……

1

0。125

x

2

=

0。25

……

0

0。25

x

2

=

0。5

……

0

0。5

x

2

=

1

……

1

結果為得到的整數位按照從左往右排列

1011001

複製程式碼

將計算後的 000 111 序列拼在一起就得到轉換的二進位制 1101010。10110011101010。10110011101010。1011001,用科學計數法表示為1。1010101011001261。1010101011001*2^61。101010101100126,算出了二進位制,接下來需要將它存進計算機中,在Javascript中不區分整數和小數,數字統一按照雙精度浮點數的要求來儲存,主要包含下面規則:

使用 8bytes(64bits)8bytes(64bits)8bytes(64bits) 儲存雙精度浮點數

儲存小數用科學計數法表示的資料

第一位表示符號,後 111111 位表示指數,

指數按照補位運算

,即直接 102310231023 加指數位

剩餘 525252 位表示小數點後的尾數,

超過 525252 位的部分 000 舍 111 進

由於指數位的 11 位不包括符號位,那麼為了達到正負指數的效果,就引入了

指數的偏移值

用圖表示如下:

理解 JavaScript 的記憶體與變數儲存

Screen Shot 2021-08-17 at 12。20。14 PM。png

我們將轉換好的二進位制數按規則放進記憶體中,首先 106。6953125106。6953125106。6953125 是正數,所以符號位應該為 000, 000 表示正號, 111 表示負號

理解 JavaScript 的記憶體與變數儲存

Screen Shot 2021-08-17 at 12。20。22 PM。png

二進位制 1。1010101011001261。1010101011001*2^61。101010101100126 指數是 666(這裡需要加上偏移量1023),轉成二進位制為 100000001011000000010110000000101,指數位要求放置二進位制的補碼,而補碼的計算規則是:

正數的補碼就是其本身

負數的補碼是在其原碼的基礎上, 符號位不變, 其餘各位取反, 最後+1。 (即在反碼的基礎上+1)

[+

1

] = [

00000001

]原 = [

00000001

]反

-1

] = [

10000001

]原 = [

11111110

]反

複製程式碼

所以圖片指數位應該填

理解 JavaScript 的記憶體與變數儲存

Screen Shot 2021-08-17 at 12。20。47 PM。png

尾數位部分直接將小數轉換後的二進位制填入即可

理解 JavaScript 的記憶體與變數儲存

Screen Shot 2021-08-17 at 12。21。37 PM。png

數字最後就是以這樣的形式存入計算機中

why 0。1 + 0。2 !== 0。3?

在理解數字儲存的原理後,我們再來分析下為什麼 0。1+0。2!==0。30。1 + 0。2 !== 0。30。1+0。2!==0。3

首先將 0。10。10。1 0。20。20。2 0。30。30。3 分別轉換成二進位制

0。1

x

2

=

0。2

……

0

0。2

x

2

=

0。4

……

0

0。4

x

2

=

0。8

……

0

0。8

x

2

=

1。6

……

1

0。6

x

2

=

1。2

……

1

0。2

x

2

=

0。4

……

0

0。4

x

2

=

0。8

……

0

0。8

x

2

=

1。6

……

1

0。6

x

2

=

1。2

……

1

得到的整數位按照從左往右排列

000110011。

。。

複製程式碼

0。1→0。00011(0011)∞0。1 \rightarrow 0。00011(0011)_\infty0。1→0。00011(0011)∞

0。2

x

2

=

0。4

……

0

0。4

x

2

=

0。8

……

0

0。8

x

2

=

1。6

……

1

0。6

x

2

=

1。2

……

1

0。2

x

2

=

0。4

……

0

0。4

x

2

=

0。8

……

0

0。8

x

2

=

1。6

……

1

0。6

x

2

=

1。2

……

1

0。2

x

2

=

0。4

……

0

得到的整數位按照從左往右排列

001100110。

。。

複製程式碼

0。2→0。00110(0110)∞0。2 \rightarrow 0。00110(0110)_\infty0。2→0。00110(0110)∞

0。3

x

2

=

0。6

……

0

0。6

x

2

=

1。2

……

1

0。2

x

2

=

0。4

……

0

0。4

x

2

=

0。8

……

0

0。8

x

2

=

1。6

……

1

0。6

x

2

=

1。2

……

1

0。2

x

2

=

0。4

……

0

0。4

x

2

=

0。8

……

0

0。8

x

2

=

1。6

……

1

得到的整數位按照從左往右排列

010011001。

。。

複製程式碼

0。3→0。01001(1001)∞0。3 \rightarrow 0。01001(1001)_\infty0。3→0。01001(1001)∞

統一用科學計數法表示為

0。1→0。00011(0011)∞→1。(1001)∞240。1 \rightarrow 0。00011(0011)_\infty \rightarrow 1。(1001)_\infty*2^{-4}0。1→0。00011(0011)∞→1。(1001)∞24

0。2→0。00110(0110)∞→1。(1001)∞230。2 \rightarrow 0。00110(0110)_\infty \rightarrow 1。(1001)_\infty*2^{-3}0。2→0。00110(0110)∞→1。(1001)∞23

0。3→0。01001(1001)∞→1。(0011)∞220。3 \rightarrow 0。01001(1001)_\infty \rightarrow 1。(0011)_\infty*2^{-2}0。3→0。01001(1001)∞→1。(0011)∞22

放入計算機中雙精度浮點數儲存,最後的紅色表示超過尾數位的二進位制,即需要做舍0進1處理

理解 JavaScript 的記憶體與變數儲存

Screen Shot 2021-08-17 at 12。30。01 PM。png

理解 JavaScript 的記憶體與變數儲存

Screen Shot 2021-08-17 at 12。30。27 PM。png

理解 JavaScript 的記憶體與變數儲存

Screen Shot 2021-08-17 at 12。32。27 PM。png

則經過64位雙精度儲存後,二進位制如下表示

0。1→001111111011(1001)1210100。1 \rightarrow 0-01111111011-(1001)_{12}10100。1→001111111011(1001)121010

0。2→001111111100(1001)1210100。2 \rightarrow 0-01111111100-(1001)_{12}10100。2→001111111100(1001)121010

0。3→001111111101(0011)1200110。3 \rightarrow 0-01111111101-(0011)_{12}00110。3→001111111101(0011)120011

此時 0。1+0。20。1 + 0。20。1+0。2 可以看出與 0。30。30。3 不相等

理解 JavaScript 的記憶體與變數儲存

8。png

這就是數字在計算機中運算往往會給人帶來一些“驚喜”!

結束語

如果該文對您有幫助的話,請點個贊哦

文中若有錯誤,歡迎指正;若您有補充,歡迎留言。

關於本文

作者:立花正仁

https://juejin。cn/po

st/6991844682066034718

- END -

寫在最後

我是

懸筆e絕

,如果我的文章對你有幫助,請點個

支援我一下

若有什麼疑問,也可以加我微信:

yllg_xbyj

,一起交流心得

看完三件事

如果你覺得這篇內容對你挺有啟發,我想邀請你幫我三個小忙:

點個「

在看

」,讓更多的人也能看到這篇內容(喜歡不點在看,都是耍流氓 -_-)

關注公眾號「

懸筆e絕

」,持續為你推送精選好文,

回覆「

加群

」加入交流群

點一下,程式碼無 Bug

理解 JavaScript 的記憶體與變數儲存