JS 有七種數(shù)據(jù)類型:
數(shù)值(number):整數(shù)和小數(shù)(比如1和3.14)
字符串(string):字符組成的文本(比如”Hello World”)
布爾值(boolean):true(真)和false(假)兩個特定值
undefined:表示“未定義”或不存在
null:表示無值,即此處的值就是“無”的狀態(tài)
對象(object):各種值組成的集合
數(shù)據(jù)類型Symbol:表示獨一無二的值 (ES6中加入的)
其中數(shù)值、字符串、布爾值、Undefined、Null稱為原始類型
而對象被稱為引用類型, 又可以分為三個子類型:
狹義的對象(object)
數(shù)組(array)
函數(shù)(function)
廣義上來說JavaScript的所有數(shù)據(jù)包括原始類型的數(shù)據(jù)(數(shù)值,字符串,布爾值)都可以視為對象。而一般來講我們平時說的‘對象’特指狹義的對象。
- 原始值
存儲在棧(stack)中的簡單數(shù)據(jù)段,也就是說,它們的值直接存儲在變量訪問的位置。 -
引用值
存儲在堆(heap)中的對象,也就是說,存儲在變量處的值是一個指針(point),指向存儲對象的內(nèi)存處。
存儲在堆和棧中的原始值和引用值
知道這些有什么用呢?主要跟數(shù)據(jù)的賦值,拷貝有關。
我們先來看原始值的例子:

我們將a 賦值給a_2,b賦值給b_2,c賦值給c_2。然后輸出,發(fā)現(xiàn)a_2,b_2,c_2的值是和a,b,c一樣的。然后我們修改了a,b,c的值。再打印a_2,b_2,c_2發(fā)現(xiàn)他們的值并沒有隨著a,b,c的改變而改變。說明a_2,b_2,c_2是a,b,c的一份拷貝或者說深拷貝(原始類型的拷貝都是深拷貝),他們之間已經(jīng)互不影響了。
用圖來表示棧中的變化:



再來看看引用類型的賦值 拷貝

可以看到,當我們改變a[0]時,a_2也被改變了。改變b.name時,b_2也被改變了。說明a_2,b_2與a,b是相互關聯(lián)的。我們看看存儲空間里的情況:

a,b在棧中保存的是一個指針,指向堆中的一個地址。

可以看到與原始類型不同,引用類型賦值拷貝的時候a_2,b_2被賦予的是a,b在棧中保存的指針。所以,a與a_2指向同一個堆存儲地址,b與b_2指向同一個堆存儲地址。
當我們通過a[0]或者通過b.name改變值的時候其實是改變了堆存儲空間中的值。所以a_2,b_2獲取值時我們看到的結果是也被改變了。
所以引用類型賦值拷貝時是淺拷貝,只是拷貝了指針,而沒有拷貝指針指向的值。也可以理解為a_2是a的一個別名,b_2是b的一個別名。比如你本名叫張三,網(wǎng)名叫忘了愛。那么張三和忘了愛其實都是你,別人找張三,找忘了愛找的也都是你。
講這么多數(shù)據(jù)類型和深拷貝淺拷貝的。是因為當項目比較大的時候,我們?nèi)绻桓闱宄覀儌鞯氖窃贾颠€是引用值那么有時就會引起問題。

如果我們有個函數(shù)需要傳個對象參數(shù),然后在函數(shù)中我們會做一些操作,可能會改變了對象中的一個屬性值。那這時候我們要意識到這是不是你想要的結果。(基本的情況是都不是我們想要的)
有一項編寫原則是 不要直接改變函數(shù)傳入?yún)?shù)的值,除非你清楚后果。
