JavaScript中原始值和引用值深入講解
值和引用相關內容
在 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ù)類型的值又被稱之為復雜值或引用值。
那么兩者之間具體有什么區(qū)別呢?我們一點一點來看:
1. 簡單值(原始值)
簡單值是表示 JavaScript 中可用的數(shù)據(jù)或信息的最底層形式或最簡單形式。簡單類型的值被稱為簡單值,是因為它們是不可細化的。
也就是說,數(shù)字是數(shù)字,字符串是字符串,布爾值是 true 或 false,null 和 undefined 就是 null 和 undefined。這些值本身很簡單,不能夠再進行拆分。
由于簡單值的數(shù)據(jù)大小是固定的,所以簡單值的數(shù)據(jù)是存儲于內存中的棧區(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 從第一個版本開始時的一個 bug,并且這個 bug 無法被修復。因為修復會破壞現(xiàn)有的代碼。
具體原因是因為不同的對象在底層都表現(xiàn)為二進制,在 JavaScript 中二進制前三位都為 0 的話會被判斷為 object 類型,null 的二進制全部為 0,自然前三位也是 0,所以執(zhí)行 typeof 值會返回 object。
例外,當我們打印 null == undefined 的時候,返回的是 true,這也是面試時經(jīng)常會被問到的一個問題。
這兩個值都表示“無”的意思。
通常情況下, 當我們試圖訪問某個不存在的或者沒有賦值的變量時,就會得到一個 undefined 值。Javascript 會自動將聲明是沒有進行初始化的變量設為 undifined。
而 null 值表示空,null 不能通過 Javascript 來自動賦值,也就是說必須要我們自己手動來給某個變量賦值為 null。
那么為什么 JavaScript 要設置兩個表示"無"的值呢?
這其實也是因為歷史原因。
1995 年 JavaScript 誕生時,最初像 Java 一樣,只設置了 null 作為表示"無"的值。根據(jù) C 語言的傳統(tǒng),null 被設計成可以自動轉為 0。
但是,JavaScript 的設計者,覺得這樣做還不夠,主要有以下兩個原因。
- null 像在 Java 里一樣,被當成一個對象。但是,JavaScript 的數(shù)據(jù)類型分成原始類型(primitive)和復合類型(complex)兩大類,作者覺得表示“無”的值最好不是對象。
- JavaScript 的最初版本沒有包括錯誤處理機制,發(fā)生數(shù)據(jù)類型不匹配時,往往是自動轉換類型或者默默地失敗。作者覺得,如果 null 自動轉為 0,很不容易發(fā)現(xiàn)錯誤。
因此,作者又設計了一個 undefined。這里注意:先有 null 后有 undefined 出來,undefined 是為了填補之前的坑。
JavaScript 的最初版本是這樣區(qū)分的:
null 是一個表示“無”的對象(空對象指針),轉為數(shù)值時為 0;
典型用法是:
- 作為函數(shù)的參數(shù),表示該函數(shù)的參數(shù)不是對象。
- 作為對象原型鏈的終點。
undefined 是一個表示"無"的原始值,轉為數(shù)值時為 NaN。
典型用法是:
- 變量被聲明了,但沒有賦值時,就等于 undefined。
- 調用函數(shù)時,應該提供的參數(shù)沒有提供,該參數(shù)等于 undefined。
- 對象沒有賦值的屬性,該屬性的值為 undefined。
- 函數(shù)沒有返回值時,默認返回 undefined。
2. 復雜值(引用值)
在 JavaScript 中,對象就是一個復雜值。因為對象可以向下拆分,拆分成多個簡單值或者復雜值。
復雜值在內存中的大小是未知的,因為復雜值可以包含任何值,而不是一個特定的已知值,所以復雜值的數(shù)據(jù)都是存儲于堆區(qū)里面。
如下圖所示:
下面是具體的代碼示例:
// 簡單值 var a1 = 0; var a2 = "this is str"; var a3 = null // 復雜值 var c = [1, 2, 3]; var d = {m: 20};
3. 訪問方式
按值訪問
簡單值是作為不可細化的值進行存儲和使用的,引用它們會轉移其值。
var str = "Hello"; var str2 = str; str = null; console.log(str,str2); // null "Hello"
引用訪問
復雜值是通過引用進行存儲和操作的,而不是實際的值。創(chuàng)建一個包含復雜對象的變量時,其值是內存中的一個引用地址。引用一個復雜對象時,使用它的名稱(即變量或對象屬性)通過內存中的引用地址獲取該對象值。
var obj = {}; var obj2 = obj; obj.name = "zhangsan"; console.log(obj.name); // zhangsan console.log(obj2.name); // zhangsan
4. 比較方式
簡單值采用值比較,而復雜值采用引用比較。復雜值只有在引用相同的對象(即有相同的地址)時才相等。即使是包含相同對象的兩個變量也彼此不相等,因為它們并不指向同一個對象。
示例 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. 動態(tài)屬性
對于復雜值,可以為其添加屬性和方法,也可以改變和刪除其屬性和方法。但簡單值不可以:
var str = 'test'; str.abc = true; console.log(str.abc); // undefined var obj = {}; obj.abc = true; console.log(obj.abc); // true
復雜值支持動態(tài)對象屬性,因為我們可以定義對象,然后創(chuàng)建引用,再更新對象,并且所有指向該對象的變量都會獲得更新。
一個新變量指向現(xiàn)有的復雜對象,并沒有復制該對象。這就是復雜值有時被稱為引用值的原因。復雜值可以根據(jù)需求有任意多個引用,即使對象改變,它們也總是指向同一個對象
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. 變量賦值
最后說一下關于變量的賦值,其實是可以分為直接賦值和引用賦值的。直接賦值,就是指將簡單值賦值給變量,而引用賦值是指將一個復雜值的引用賦值給變量,這個引用指向堆區(qū)實際存在的數(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ù)類型的值又被稱之為復雜值或引用值。
兩者的區(qū)別在于:
原始值是表示 JavaScript 中可用的數(shù)據(jù)或信息的最底層形式或最簡單形式。簡單類型的值被稱為原始值,是因為它們是不可細化的。
也就是說,數(shù)字是數(shù)字,字符是字符,布爾值是 true 或 false,null 和 undefined 就是 null 和 undefined。這些值本身很簡單,不能夠再進行拆分。由于原始值的數(shù)據(jù)大小是固定的,所以原始值的數(shù)據(jù)是存儲于內存中的棧區(qū)里面的。
在 JavaScript 中,對象就是一個引用值。因為對象可以向下拆分,拆分成多個簡單值或者復雜值。引用值在內存中的大小是未知的,因為引用值可以包含任何值,而不是一個特定的已知值,所以引用值的數(shù)據(jù)都是存儲于堆區(qū)里面。
最后總結一下兩者的區(qū)別:
訪問方式
- 原始值:訪問到的是值
- 引用值:訪問到的是引用地址
比較方式
- 原始值:比較的是值
- 引用值:比較的是地址
動態(tài)屬性
- 原始值:無法添加動態(tài)屬性
- 引用值:可以添加動態(tài)屬性
變量賦值
- 原始值:賦值的是值
- 引用值:賦值的是地址
總結
到此這篇關于JavaScript中原始值和引用值的文章就介紹到這了,更多相關js原始值和引用值內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
javascript中Date format(js日期格式化)方法小結
這篇文章主要介紹了javascript中Date format,即js日期格式化的方法.實例總結了三種常見的JavaScript日期格式化技巧,需要的朋友可以參考下2015-12-12JavaScript(js)處理的HTML事件、鍵盤事件、鼠標事件簡單示例
這篇文章主要介紹了JavaScript(js)處理的HTML事件、鍵盤事件、鼠標事件,結合實例形式分析了JavaScript針對HTML事件、鍵盤事件及鼠標事件的簡單處理方法,需要的朋友可以參考下2019-11-11