JavaScript中原始值和引用值深入講解
值和引用相關(guān)內(nèi)容
在 JavaScript 中,數(shù)據(jù)類型整體上來講可以分為兩大類:基本類型和引用數(shù)據(jù)類型
基本數(shù)據(jù)類型,一共有 6 種:
string,symbol,number,boolean,undefined,null
其中 symbol 類型是在 ES6 里面新添加的基本數(shù)據(jù)類型。
引用數(shù)據(jù)類型,就只有 1 種:
object
基本數(shù)據(jù)類型的值又被稱之為原始值或簡單值,而引用數(shù)據(jù)類型的值又被稱之為復(fù)雜值或引用值。
那么兩者之間具體有什么區(qū)別呢?我們一點(diǎn)一點(diǎn)來看:
1. 簡單值(原始值)
簡單值是表示 JavaScript 中可用的數(shù)據(jù)或信息的最底層形式或最簡單形式。簡單類型的值被稱為簡單值,是因?yàn)樗鼈兪?/strong>不可細(xì)化的。
也就是說,數(shù)字是數(shù)字,字符串是字符串,布爾值是 true 或 false,null 和 undefined 就是 null 和 undefined。這些值本身很簡單,不能夠再進(jìn)行拆分。
由于簡單值的數(shù)據(jù)大小是固定的,所以簡單值的數(shù)據(jù)是存儲(chǔ)于內(nèi)存中的棧區(qū)里面的。
要簡單理解棧的存取方式,我們可以通過類比乒乓球盒子來分析。如下圖:
下面是具體的代碼示例:
var str = "Hello World"; var num = 10; var bol = true; var myNull = null; var undef = undefined; console.log(typeof str); // string console.log(typeof num); // number console.log(typeof bol); // boolean console.log(typeof myNull); // object console.log(typeof undef); // undefined
這里面 null 比較特殊,打印出來是 object,這是由于歷史原因所遺留下來的問題。
是來源于 JavaScript 從第一個(gè)版本開始時(shí)的一個(gè) bug,并且這個(gè) bug 無法被修復(fù)。因?yàn)樾迯?fù)會(huì)破壞現(xiàn)有的代碼。
具體原因是因?yàn)椴煌膶ο笤诘讓佣急憩F(xiàn)為二進(jìn)制,在 JavaScript 中二進(jìn)制前三位都為 0 的話會(huì)被判斷為 object 類型,null 的二進(jìn)制全部為 0,自然前三位也是 0,所以執(zhí)行 typeof 值會(huì)返回 object。
例外,當(dāng)我們打印 null == undefined 的時(shí)候,返回的是 true,這也是面試時(shí)經(jīng)常會(huì)被問到的一個(gè)問題。
這兩個(gè)值都表示“無”的意思。
通常情況下, 當(dāng)我們試圖訪問某個(gè)不存在的或者沒有賦值的變量時(shí),就會(huì)得到一個(gè) undefined 值。Javascript 會(huì)自動(dòng)將聲明是沒有進(jìn)行初始化的變量設(shè)為 undifined。
而 null 值表示空,null 不能通過 Javascript 來自動(dòng)賦值,也就是說必須要我們自己手動(dòng)來給某個(gè)變量賦值為 null。
那么為什么 JavaScript 要設(shè)置兩個(gè)表示"無"的值呢?
這其實(shí)也是因?yàn)闅v史原因。
1995 年 JavaScript 誕生時(shí),最初像 Java 一樣,只設(shè)置了 null 作為表示"無"的值。根據(jù) C 語言的傳統(tǒng),null 被設(shè)計(jì)成可以自動(dòng)轉(zhuǎn)為 0。
但是,JavaScript 的設(shè)計(jì)者,覺得這樣做還不夠,主要有以下兩個(gè)原因。
- null 像在 Java 里一樣,被當(dāng)成一個(gè)對象。但是,JavaScript 的數(shù)據(jù)類型分成原始類型(primitive)和復(fù)合類型(complex)兩大類,作者覺得表示“無”的值最好不是對象。
- JavaScript 的最初版本沒有包括錯(cuò)誤處理機(jī)制,發(fā)生數(shù)據(jù)類型不匹配時(shí),往往是自動(dòng)轉(zhuǎn)換類型或者默默地失敗。作者覺得,如果 null 自動(dòng)轉(zhuǎn)為 0,很不容易發(fā)現(xiàn)錯(cuò)誤。
因此,作者又設(shè)計(jì)了一個(gè) undefined。這里注意:先有 null 后有 undefined 出來,undefined 是為了填補(bǔ)之前的坑。
JavaScript 的最初版本是這樣區(qū)分的:
null 是一個(gè)表示“無”的對象(空對象指針),轉(zhuǎn)為數(shù)值時(shí)為 0;
典型用法是:
- 作為函數(shù)的參數(shù),表示該函數(shù)的參數(shù)不是對象。
- 作為對象原型鏈的終點(diǎn)。
undefined 是一個(gè)表示"無"的原始值,轉(zhuǎn)為數(shù)值時(shí)為 NaN。
典型用法是:
- 變量被聲明了,但沒有賦值時(shí),就等于 undefined。
- 調(diào)用函數(shù)時(shí),應(yīng)該提供的參數(shù)沒有提供,該參數(shù)等于 undefined。
- 對象沒有賦值的屬性,該屬性的值為 undefined。
- 函數(shù)沒有返回值時(shí),默認(rèn)返回 undefined。
2. 復(fù)雜值(引用值)
在 JavaScript 中,對象就是一個(gè)復(fù)雜值。因?yàn)閷ο罂梢韵蛳虏鸱?,拆分成多個(gè)簡單值或者復(fù)雜值。
復(fù)雜值在內(nèi)存中的大小是未知的,因?yàn)閺?fù)雜值可以包含任何值,而不是一個(gè)特定的已知值,所以復(fù)雜值的數(shù)據(jù)都是存儲(chǔ)于堆區(qū)里面。
如下圖所示:
下面是具體的代碼示例:
// 簡單值 var a1 = 0; var a2 = "this is str"; var a3 = null // 復(fù)雜值 var c = [1, 2, 3]; var d = {m: 20};
3. 訪問方式
按值訪問
簡單值是作為不可細(xì)化的值進(jìn)行存儲(chǔ)和使用的,引用它們會(huì)轉(zhuǎn)移其值。
var str = "Hello"; var str2 = str; str = null; console.log(str,str2); // null "Hello"
引用訪問
復(fù)雜值是通過引用進(jìn)行存儲(chǔ)和操作的,而不是實(shí)際的值。創(chuàng)建一個(gè)包含復(fù)雜對象的變量時(shí),其值是內(nèi)存中的一個(gè)引用地址。引用一個(gè)復(fù)雜對象時(shí),使用它的名稱(即變量或?qū)ο髮傩裕┩ㄟ^內(nèi)存中的引用地址獲取該對象值。
var obj = {}; var obj2 = obj; obj.name = "zhangsan"; console.log(obj.name); // zhangsan console.log(obj2.name); // zhangsan
4. 比較方式
簡單值采用值比較,而復(fù)雜值采用引用比較。復(fù)雜值只有在引用相同的對象(即有相同的地址)時(shí)才相等。即使是包含相同對象的兩個(gè)變量也彼此不相等,因?yàn)樗鼈儾⒉恢赶蛲粋€(gè)對象。
示例 1:
var a = 10; var b = 10; var c = new Number(10); var d = c; console.log(a === b); // true console.log(a === c); // false console.log(a === c); // false console.log(a == c); // true d = 10; console.log(d == c); // true console.log(d === c); // false
示例 2:
var obj = {name : 'zhangsan'}; var obj2 = {name : 'zhangsan'}; console.log(obj == obj2); // false console.log(obj === obj2); // false var obj3 = {name : 'zhangsan'}; var obj4 = obj3; console.log(obj3 == obj4); // true console.log(obj3 === obj4); // ture
5. 動(dòng)態(tài)屬性
對于復(fù)雜值,可以為其添加屬性和方法,也可以改變和刪除其屬性和方法。但簡單值不可以:
var str = 'test'; str.abc = true; console.log(str.abc); // undefined var obj = {}; obj.abc = true; console.log(obj.abc); // true
復(fù)雜值支持動(dòng)態(tài)對象屬性,因?yàn)槲覀兛梢远x對象,然后創(chuàng)建引用,再更新對象,并且所有指向該對象的變量都會(huì)獲得更新。
一個(gè)新變量指向現(xiàn)有的復(fù)雜對象,并沒有復(fù)制該對象。這就是復(fù)雜值有時(shí)被稱為引用值的原因。復(fù)雜值可以根據(jù)需求有任意多個(gè)引用,即使對象改變,它們也總是指向同一個(gè)對象
var obj = {name : 'zhangsan'}; var obj2 = obj; var obj3 = obj2; obj.name = 'abc'; console.log(obj.name, obj2.name, obj3.name); // abc abc abc
6. 變量賦值
最后說一下關(guān)于變量的賦值,其實(shí)是可以分為直接賦值和引用賦值的。直接賦值,就是指將簡單值賦值給變量,而引用賦值是指將一個(gè)復(fù)雜值的引用賦值給變量,這個(gè)引用指向堆區(qū)實(shí)際存在的數(shù)據(jù)。
直接賦值
var a = 3; var b = a; b = 5; console.log(a); // 3
引用賦值
var a = {value : 1}; var b = a; b.value = 10; console.log(a.value); // 10
靈魂拷問
- JS 的基本數(shù)據(jù)類型有哪些?基本數(shù)據(jù)類型和引用數(shù)據(jù)類型的區(qū)別
參考答案:
在 JavaScript 中,數(shù)據(jù)類型整體上來講可以分為兩大類:基本類型和引用數(shù)據(jù)類型
基本數(shù)據(jù)類型,一共有 6 種:
string,symbol,number,boolean,undefined,null其中 symbol 類型是在 ES6 里面新添加的基本數(shù)據(jù)類型。
引用數(shù)據(jù)類型,就只有 1 種:
object基本數(shù)據(jù)類型的值又被稱之為原始值或簡單值,而引用數(shù)據(jù)類型的值又被稱之為復(fù)雜值或引用值。
兩者的區(qū)別在于:
原始值是表示 JavaScript 中可用的數(shù)據(jù)或信息的最底層形式或最簡單形式。簡單類型的值被稱為原始值,是因?yàn)樗鼈兪?/strong>不可細(xì)化的。
也就是說,數(shù)字是數(shù)字,字符是字符,布爾值是 true 或 false,null 和 undefined 就是 null 和 undefined。這些值本身很簡單,不能夠再進(jìn)行拆分。由于原始值的數(shù)據(jù)大小是固定的,所以原始值的數(shù)據(jù)是存儲(chǔ)于內(nèi)存中的棧區(qū)里面的。
在 JavaScript 中,對象就是一個(gè)引用值。因?yàn)閷ο罂梢韵蛳虏鸱?,拆分成多個(gè)簡單值或者復(fù)雜值。引用值在內(nèi)存中的大小是未知的,因?yàn)橐弥悼梢园魏沃?,而不是一個(gè)特定的已知值,所以引用值的數(shù)據(jù)都是存儲(chǔ)于堆區(qū)里面。
最后總結(jié)一下兩者的區(qū)別:
訪問方式
- 原始值:訪問到的是值
- 引用值:訪問到的是引用地址
比較方式
- 原始值:比較的是值
- 引用值:比較的是地址
動(dòng)態(tài)屬性
- 原始值:無法添加動(dòng)態(tài)屬性
- 引用值:可以添加動(dòng)態(tài)屬性
變量賦值
- 原始值:賦值的是值
- 引用值:賦值的是地址
總結(jié)
到此這篇關(guān)于JavaScript中原始值和引用值的文章就介紹到這了,更多相關(guān)js原始值和引用值內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
javascript中Date format(js日期格式化)方法小結(jié)
這篇文章主要介紹了javascript中Date format,即js日期格式化的方法.實(shí)例總結(jié)了三種常見的JavaScript日期格式化技巧,需要的朋友可以參考下2015-12-12Angularjs手動(dòng)解析表達(dá)式($parse)
這篇文章主要介紹了Angularjs手動(dòng)解析表達(dá)式($parse)的相關(guān)資料,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下2016-10-10用js實(shí)現(xiàn)隨機(jī)返回?cái)?shù)組的一個(gè)元素
js實(shí)現(xiàn)隨機(jī)返回?cái)?shù)組的一個(gè)元素,這是個(gè)奇妙的方法。適合做標(biāo)題性質(zhì)文字的隨機(jī)輪換顯示2007-08-08使用javaScript實(shí)現(xiàn)鼠標(biāo)拖拽事件
這篇文章主要為大家詳細(xì)介紹了使用javaScript實(shí)現(xiàn)鼠標(biāo)拖拽事件的相關(guān)資料,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-09-09JavaScript(js)處理的HTML事件、鍵盤事件、鼠標(biāo)事件簡單示例
這篇文章主要介紹了JavaScript(js)處理的HTML事件、鍵盤事件、鼠標(biāo)事件,結(jié)合實(shí)例形式分析了JavaScript針對HTML事件、鍵盤事件及鼠標(biāo)事件的簡單處理方法,需要的朋友可以參考下2019-11-11js+css實(shí)現(xiàn)三級(jí)導(dǎo)航菜單
這篇文章主要為大家詳細(xì)介紹了js+css實(shí)現(xiàn)三級(jí)導(dǎo)航菜單,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-08-08