JavaScript數據類型和他背後不得不說的故事

基本概念

ECMAScript 中有 5 種簡單數據類型(也稱爲基本數據類型,存放在棧中):Undefined、Null、Boolean、NumberString。還有 1 種複雜數據類型——Object(存放在堆內存中)。ES6的Symbol暫且不論。
1018967-20180718111209824-912970736.png
1018967-20180718115535028-421997257.png編程

簡單粗暴地描述一下這幾個類型:

  1. Undefined 類型只有一個值,即特殊的 undefined。在使用 var 聲明變量但未對其加以初始化時,這個變量的值就是 undefined,例如:編程語言

    var message;
    alert(message == undefined); //true
  2. Null 類型是第二個只有一個值的數據類型,這個特殊的值是 null。從邏輯角度來看,null 值表示一個空對象指針。
  3. Boolean類型:truefalse
  4. Number類型:阿拉伯數字的(八進制、十進制、十六進制、整數、浮點數、5e-324 ~ 1.7976931348623157e+30八、NaN……)。
  5. String類型:帶引號的,單引號雙引號均可以(字符串),還有一些特殊的字符字面量(\n之類的)函數

    var firstName = "Nicholas";
    var lastName = 'Zakas';
  6. Object類型:ECMAScript 中的對象其實就是一組數據和功能的集合(萬物皆對象😄)。對象能夠經過執行 new 操做符後跟要建立 的對象類型的名稱來建立。而建立 Object 類型的實例併爲其添加屬性和(或)方法,就能夠建立自定義對象,以下所示:spa

    var o = new Object();

typeof操做符

鑑於 ECMAScript 是鬆散類型的,所以須要有一種手段來檢測給定變量的數據類型——typeof就是負責提供這方面信息的操做符。對一個值使用 typeof 操做符可能返回下列某個字符串:設計

  • "undefined"——若是這個值未定義;
  • "boolean"——若是這個值是布爾值;
  • "string"——若是這個值是字符串;
  • "number"——若是這個值是數值;
  • "object"——若是這個值是對象或 null;
  • "function"——若是這個值是函數。

有一些須要注意的地方:

  1. 有些時候,typeof 操做符會返回一些使人迷惑但技術上卻正確的值。好比,調用typeof null會返回"object",由於特殊值null被認爲是一個空的對象引用。從邏輯角度來看,null 值表示一個空對象指針,而這也正是使用typeof操做符檢測null值時會返回"object"的緣由。
  2. 首先,任何涉及 NaN 的操做(例如 NaN/10)都會返回 NaN,這個特色在多步計算中有可能致使問題。其次,NaN與任何值都不相等,包括NaN自己。例如,下面的代碼會返回 false:3d

    alert(NaN == NaN); //false
  3. 另外,NaN其實是一種特殊的number指針

    typeof NaN 
    "number"
  4. 《JavaScript高級程序設計》原書上寫道:「任何數值除以0都會返回NaN」,但實際上只有 0 除以 0 纔會返回 NaN,正數除以 0 返回 Infinity,負數除以 0 返回-Infinity。
  5. ECMAScript定義了isNaN()函數幫咱們肯定這個參數是否「不是數值」。isNaN()在接收到一個值以後,會嘗試 將這個值轉換爲數值。某些不是數值的值會直接轉換爲數值。下面看幾個例子:
alert(isNaN(NaN));      //true
    alert(isNaN(10));       //false(10 是一個數值)
    alert(isNaN("10"));     //false(能夠被轉換成數值 10)
    alert(isNaN("blue"));   //true(不能轉換成數值)
    alert(isNaN(true));     //false(能夠被轉換成數值 1)

再來看一張圖:

v2-80f03dfe036ad4ff0e37150aa7938994_1200x500.jpg

若是被這我的猥瑣的笑容嚇到了能夠先看最下面的《JavaScript高級程序設計》原理部分。code

下面對圖上的內容進行分析

>   typeof NaN 
<·  "number"

上面已經提到,在其餘編程語言中,任何數值除以 0 都會致使錯誤,從而中止代碼執行。但在 ECMAScript 中,任何數值除以 0 會返回 NaN (原書如此,但實際上只有 0 除以 0 纔會返回 NaN,正數除以 0 返回 Infinity,負數除以 0 返回-Infinity),而其被定義爲number類型。對象

>   9999999999999999
<·  10000000000000000
>   0.5 + 0.1 == 0.6
<·  true
>   0.1 + 0.2 == 0.3
<·  false

這個是JavaScript的坑,若是非要究其緣由,能夠看這篇文章:js中0.1+0.2爲何不等於0.3blog

PS:在後面的冪大於20的時候會顯示成科學計數法:

>   999999999999999990000
<·  1e+21

上部分的實際結果:

>   0.5 + 0.1
<·  0.6
>   0.1 + 0.2
<·  0.30000000000000004
>   Math.max()
<·  -Infinity
>   Math.min()
<·  Infinity

Math.max() 函數返回一組數中的最大值。
若是沒有參數,則結果爲 -Infinity。
若是有任一參數不能被轉換爲數值,則結果爲 NaN。
引用自MDN

個人理解是沒有參數時,須要比較的一組值就是空,那麼空裏面的最大值就是-Infinity,Math.min()同理(我的理解,若有錯誤請指正)。

>   [] + []
<·  ""
>   [] + {}
<·  "[object Object]"
>   {} + []
<·  0
>   true + true + true === 3
<·  true
>   true - true
<·  0
>   true == 1
<·  true
>   true === 1
<·  false
>   (! + [] + [] + ![]).length
<·  9
>   9 + "1"
<·  "91"
>   91 - "1"
<·  90
>   [] == 0
<·  true

這裏的大部分運算結果涉及的類型轉化能夠參考《JavaScript高級程序設計》,文末也有摘抄。

>   true + true + true === 3
<·  true
>   true - true
<·  0
>   true == 1
<·  true
>   true === 1
<·  false

這幾個運算可能和書上寫的有些誤差,「若是有一個操做數是對象、數值或布爾值,則調用它們的 toString()方法取得相應的字符串值,而後再應用前面關於字符串的規則」,——若是是布爾值加減操做,true轉爲1,false轉爲0。

>   true + false
<·  1

再看這個

>   [] + {}
<·  "[object Object]"
>   {} + []
<·  0

[] + {}能夠理解是調用了各自的toString()方法後再應用字符串相加的規則.

>   [].toString()
<·  ""

>   var obj = {}
<·  undefined
>   obj.toString()
<·  "[object Object]"
相加結果獲得"[object Object]"

{} + []爲何結果是0?
其實是控制檯把{}當作了一個空白表達式,其實是在計算+ []。一元加運算符優先把右邊的參數轉化爲number,就獲得了0。若是是上面的obj + []獲得的結果就和[] + {}同樣都是"[object Object]"

着重看一下這個例子:
(! + [] + [] + ![]).length
首先,邏輯非!有着極高的優先級,因此首先計算的是! + []![]
+ []: + 運算符將[]轉化爲number結果爲0,![]結果爲false
式子變成了(true + [] + false).length
[].toString()爲"",true + """true""true" + false"truefalse".
"truefalse"長度爲9。


《JavaScript高級程序設計》:

加性操做符

加法 加法操做符(+)的用法以下所示:

var result = 1 + 2;
  • 若是兩個操做符都是數值,執行常規的加法計算,而後根據下列規則返回結果:
  • 若是有一個操做數是 NaN,則結果是 NaN;
  • 若是是Infinity 加 Infinity,則結果是 Infinity;
  • 若是是-Infinity加-Infinity,則結果是-Infinity;
  • 若是是 Infinity 加-Infinity,則結果是 NaN;
  • 若是是+0加+0,則結果是+0;
  • 若是是+0加-0,則結果是+0。
    不過,若是有一個操做數是字符串,那麼就要應用以下規則:
  • 若是兩個操做數都是字符串,則將第二個操做數與第一個操做數拼接起來;
  • 若是隻有一個操做數是字符串,則將另外一個操做數轉換爲字符串,而後再將兩個字符串拼接起來。
    若是有一個操做數是對象、數值或布爾值,則調用它們的 toString()方法取得相應的字符串值,
    而後再應用前面關於字符串的規則。對於 undefined 和 null,則分別調用 String()函數並取得字 符 串"undefined"和"null"。

減法 減法操做符(-)是另外一個極爲經常使用的操做符,其用法以下所示:

var result = 2 - 1;

與加法操做符相似,ECMAScript 中的減法操做符在處理各類數據類型轉換時,一樣須要遵循一些特殊規則,以下所示:

  • 若是兩個操做符都是數值,則執行常規的算術減法操做並返回結果;
  • 若是有一個操做數是 NaN,則結果是 NaN;
  • 若是是 Infinity 減 Infinity,則結果是 NaN;
  • 若是是-Infinity 減-Infinity,則結果是 NaN;
  • 若是是 Infinity 減-Infinity,則結果是 Infinity;
  • 若是是-Infinity 減 Infinity,則結果是-Infinity;
  • 若是是+0 減+0,則結果是+0;
  • 若是是+0 減-0,則結果是-0;
  • 若是是-0 減-0,則結果是+0;
  • 若是有一個操做數是字符串、布爾值、null 或 undefined,則先在後臺調用 Number()函數將其轉換爲數值,而後再根據前面的規則執行減法計算。若是轉換的結果是 NaN,則減法的結果就是 NaN;
  • 若是有一個操做數是對象,則調用對象的 valueOf()方法以取得表示該對象的數值。若是獲得的值是 NaN,則減法的結果就是 NaN。若是對象沒有 valueOf()方法,則調用其 toString()方法並將獲得的字符串轉換爲數值。

相等和不相等

ECMAScript 中的相等操做符由兩個等於號(==)表示,若是兩個操做數相等,則返回 true。而不相等操做符由歎號後跟等於號(!=)表示,若是兩個操做數不相等,則返回 true。這兩個操做符都會先轉換操做數(一般稱爲強制轉型),而後再比較它們的相等性。

在轉換不一樣的數據類型時,相等和不相等操做符遵循下列基本規則:

  • 若是有一個操做數是布爾值,則在比較相等性以前先將其轉換爲數值——false 轉換爲 0,而true 轉換爲 1;
  • 若是一個操做數是字符串,另外一個操做數是數值,在比較相等性以前先將字符串轉換爲數值;
  • 若是一個操做數是對象,另外一個操做數不是,則調用對象的 valueOf()方法,用獲得的基本類型值按照前面的規則進行比較;

這兩個操做符在進行比較時則要遵循下列規則:

  • null 和 undefined 是相等的。
  • 要比較相等性以前,不能將 null 和 undefined 轉換成其餘任何值。
PS:簡要帶幾句undefined和null的區別,想要深刻理解能夠自行查詢,這類文章也挺多的。
null 和 undefined 都表示「值的空缺」,你能夠認爲undefined是表示系統級的、出乎意料的或相似錯誤的值的空缺,而null是表示程序級的、正常的或在乎料之中的值的空缺。能夠認爲undefined表示本該有卻沒有,null是原本就沒有。undefined是未初始化的變量,null是一個空指針對象。佛語有云:「色便是空,空便是色」,「色」想要有卻沒有,「空」本就是空,指針爲空,對象爲空。然而「色便是空,空便是色」,undefined == null也成立,不是風動,不是幡動,忍者心動。
  • 若是有一個操做數是 NaN,則相等操做符返回 false,而不相等操做符返回 true。重要提示:即便兩個操做數都是 NaN,相等操做符也返回 false;由於按照規則,NaN 不等於 NaN。
  • 若是兩個操做數都是對象,則比較它們是否是同一個對象。若是兩個操做數都指向同一個對象,則相等操做符返回 true;不然,返回 false。
  • 下表列出了一些特殊狀況及比較結果:

clipboard.png


參考:

  1. 《JavaScript高級程序設計》
  2. JavaScript 神奇之旅

在下才疏學淺,如發現錯誤,請批評指正!

相關文章
相關標籤/搜索