1. 程式人生 > >web前端之JavaScript 的資料型別與變數

web前端之JavaScript 的資料型別與變數

這篇文章,我們來聊聊 JS 中的資料型別與變數。這是在學習 JS 時最基礎的一類問題,但卻很重要。希望我的分享有幫助到你。

文章開頭,我先提幾個面試中遇到的問題:

這篇文章的風格,在分析知識點的同時,插入一些我經歷過的面試題。

基本資料型別

在 JS 中,基本資料型別有 6 種,即數值、字串、布林值、null、undefined、Symbol。

對於基本資料型別,我們需要明白的是:基本型別在記憶體中的儲存方式是棧。每一個值都是單獨存放,互不影響。

基本型別都是按值訪問的。在比較時,按值進行比較:

引用資料型別

引用型別的值儲存在堆中,而引用是儲存在棧中。

引用型別按引用訪問。在比較時,也比較的引用:

引數的傳遞方式

在 JS 中,引數可以是任何型別的值,甚至可以是函式。

這裡要分析的是引數是以哪種型別傳遞的?引用型別還是基本型別?

先看一個基礎的例子:

這個例子中,我們給 addOne() 函式傳遞一個實參 out_num,這個時 out_num 會傳遞給 in_num,即內部存在著in_num = out_num的過程。最後我們看到的結果是 out_num 並沒有被函式改變,說明 in_num 和 out_num 是兩個在記憶體中獨立存放的值,即按值傳遞。

再來看一個變形:

問題來了?函式引數不是按值傳遞嗎?為什麼這裡函式內部的處理反映到外部了?這是一個超級超級超級的理解誤區。

首先,我們還是得擺正觀點,即函式引數是按值傳遞的。那這裡怎麼理解呢?對於引用型別而言,前面說引用型別分為引用和實際的記憶體空間。在這裡 out_obj 依舊傳遞給 in_obj,即in_obj = out_obj,out_obj 和 in_obj 是兩個引用,它們在記憶體中的儲存方式是獨立的,但是它們卻指向同一塊記憶體。

而in_obj.value = 1則是直接操作的實際物件。實際物件的改變,會同步到所有引用這個實際物件的引用。

你再來看這個例子,或許就會更清晰一些。

你只要抓住一點:物件的賦值就會造成引用指向的實際物件發生改變。

如何判斷資料型別

判斷資料型別,通常有三種具體的方法:

1、typeof 操作符

typeof 操作符返回一個表示資料型別的字串。它存在以下明顯的缺陷:

這是因為在 JS 語言設計之初遺留的 bug。所以 typeof 最好用於判斷一些基本型別,比如數值、字串、布林值、undefined、Symbol。

2、instanceof 操作符

typeof 的背後是通過判斷type tags來判斷資料型別,而 instanceof 則是通過判斷建構函式的 prototype 是否出現在物件原型鏈上的任何位置。

舉個例子:

也判斷自定義型別:

所以,對於字面量形式的基本資料型別,不能通過 instanceof 判斷:

3、Object.prototype.toString()

這是目前最為推薦的一種方法,可以更加精細且準確的判斷任何資料型別,甚至是 JSON、正則、日期、錯誤等等。在 Lodash 中,其判斷資料型別的核心也是 Object.prototype.toString() 方法。

4、其他

上面三種是通用的判斷資料型別的方法。面試中還會出現如何判斷一個數組、如何判斷 NaN、如何判斷類陣列物件、如何判斷一個空物件等問題。這一類問題比較開放,解決思路通常是抓住判斷資料的核心特點。

舉個例子:判斷類陣列物件。

你先要知道 JS 中類陣列物件是什麼樣子的,並尋求一個實際的參照物,比如 arguments 就是類陣列物件。那麼類陣列物件具有的特點是:真值 & 物件 & 具有 length 屬性 & length 為整數 & length 的範圍大於等於 0,小於等於最大安全正整數(Number.MAX_SAFE_INTEGER)。

在你分析特點的時候,答案就呼之欲出了。【注意全面性】

資料型別如何轉換

JS 資料型別的動態性將貫穿整個 JS 的學習,這是 JS 非常重要的特性,很多現象就是因為動態性的存在而成為 JS 獨有。

正是由於動態性,JS 的資料型別可能在你毫無察覺的情況下,就發生了改變,直到執行時報錯。

這裡主要分析下面 8 種轉換規則。

1、if 語句

if 語句中的型別轉換是最常見的。

在 if 語句中,會自動呼叫 Boolean() 轉型函式對變數 isTrue 進行轉換。

當 isTrue 的值是 null, undefined, 0, NaN, '' 時,都會轉為 false。其餘值除 false 本身外都會轉為 true。

2、Number() 轉型函式

我們重點關注 null undefined 以及字串在 Number() 下的轉換:

注意和 parseInt() 對比。

3、parseInt()

4、==

這裡需要注意的是:

null 與 undefined 的相等性是由 ECMA-262 規定的,並且 null 與 undefined 在比較相等性時不能轉換為其他任何值。

5、關係操作符

對於兩個字串的比較,是比較的字元編碼值:

一個數值,另一個其他型別,都將轉為數字進行比較。

兩個布林值轉為數值進行比較。

物件,先呼叫 valueOf(),若不存在該方法,則呼叫 toString()。

6、加法

加法中特別注意的是,數字和字串相加,將數字轉為字串。

對於物件和布林值,呼叫它們的 toString() 方法得到對應的字串值,然後進行字串相加。對於 undefined 和 null 呼叫 String() 取得字串 'undeifned' 和 'null'。

 

7、減法

對於字串、布林值、null 或者 undefined,自動呼叫 Number(),轉換結果若為 NaN,那麼最終結果為 NaN。

對於物件,先呼叫 valueOf(),如果得到 NaN,結果為 NaN。如果沒有 valueOf(),則呼叫 toString()。

8、乘法、除法

對於非數值,都會呼叫 Number() 轉型函式。

變數提升與暫時性死區

JS 中有三種宣告變數的方式:var, let, const。

var 宣告變數最大的一個特點是存在變數提升。

第一個列印結果表示,在宣告變數 a 之前,a 就已經可以訪問了,只不過並未賦值。這就是變數提升現象。(具體原因,我放在後面分析作用域的時候來寫)

let 和 const 就不存在這個問題,但是又引入了暫時性死區這樣的概念。

即宣告 a 之前,不能夠訪問 a,而直接報錯。

而暫時性死區的出現又引出另外一個問題,即 typeof 不再安全。你可以參考這篇文章http://es-discourse.com/t/why...

補充:一個經典面試題

 

我先不再這裡展開分析,我打算放到非同步與事件迴圈機制中去分析。不過這裡將 var 替換成 let 可以作為一種解決方案。如果你有興趣,也可以先去分析。

對於 const,這裡再補充一點,用於加深對基本型別和引用型別的理解。

本質上,const 並不是保證變數的值不得改動,而是變數指向的記憶體地址不得改動。

宣告全域性變數

直接通過 var 宣告全域性變數,這個全域性變數會作為 window 物件的一個屬性。

在這裡提出兩個問題,一是 let 宣告的全域性變數會成為 window 的屬性嗎?二是 var 宣告的全域性變數和直接在 window 建立屬性有沒有區別?

先來回答第一問題。let 宣告的全域性變數不會成為 window 的屬性。用什麼來支撐這樣的結論呢?在 ES6 中,對於 let 和 const 宣告的變數從一開始就形成封閉作用域。想想之前的暫時性死區。

第二個問題,var 宣告的全域性變數和直接在 window 建立屬性存在著本質的區別。先看下面的程式碼:

我們可以看到,直接建立在 window 上的屬性可以被 delete 刪除,而 var 建立的全域性屬性則不會。這是現象,通過現象看本質,二者本質上的區別在於:

使用 var 宣告的全域性變數的 [[configurable]] 資料屬性的值為 false,不能通過 delete 刪除。而直接在物件上建立的屬性預設 [[configurable]] 的值為 true,即可以被 delete 刪除。(關於 [[configurable]] 屬性,在後面的文章中分析物件的時候還會提到)

小結

在這篇「資料型別與變數」文章中,分析了 7 個大類。再來回顧一下:

基本型別、引用型別、引數傳遞方式、如何判斷資料型別、資料型別如何轉換、變數提升與暫時性死區、宣告全域性變數。

這些不僅是校招面試中的高頻考點,也是學習 JS 必不可少的知識點。

Tip1:《JavaScript 高階程式設計》這本書被稱作“前端的聖經”是有原因的。對於正在準備校園招聘的你,非常有必要!書讀百遍,其義自見。你會發現你在面試中遇到的絕大部分 JS 相關的知識點都能在這本書中找到“答案”!

Tip2:在準備複習的過程中,注意知識的模組性與相關性。你得有自己劃分知識模組的能力,比如今天的「資料型別與變數」模組。相關性是指,任何的知識都是由聯絡的,比如這裡牽涉到作用域、記憶體等模組。

最後“相信有很多想學前端的小夥伴,今年年初我花了一個月整理了一份最適合2018年學習的web前端乾貨,從最基礎的HTML+CSS+JS到移動端HTML5等都有整理,送給每一位前端小夥伴,53763,1707這裡是小白聚集地,歡迎初學和進階中的小夥伴。”

祝大家早日學有所成,拿到滿意offer,快速升職加薪,走上人生巔峰。