JavaScript基本語法(二)——數(shù)據(jù)類型

常用數(shù)據(jù)類型#

ECMAScript有6種簡單的數(shù)據(jù)類型(原始類型):Undefined,Null,Boolean,Number,String和Symbol(ES6新增Symbol類型的值,在此不會過多涉及)
此外還有一種復(fù)雜的數(shù)據(jù)類型:Object
在ECMAScript中無法定義自己的數(shù)據(jù)類型,所有值都必須采用以上七種數(shù)據(jù)類型之一來進(jìn)行表示,好在ECMAScript數(shù)據(jù)類型比較靈活,一種數(shù)據(jù)類型可以當(dāng)做多種數(shù)據(jù)類型進(jìn)行使用
其中,數(shù)值、字符串、布爾值這三種類型合稱為原始類型的值,即這三種類型是最基本的數(shù)據(jù)類型,無法繼續(xù)細(xì)分。對象則稱為合成類型的值,因為一個對象往往是多個原始類型的值所組成,可以看做一個存放各種值的容器。至于undefined和null,一般將他們視為兩個特殊的值。

typeof 操作符##

一種用來確定任意變量的數(shù)據(jù)類型的手段,對一個變量使用typeof操作符會返回下列字符串其一:
“undefined”表示值未定義
“boolean”表示值為布爾值
“string”表示值為字符串
“number”表示值為數(shù)字
“object”表示值為對象(不是函數(shù))或null
“function”表示值為函數(shù)
“symbol”表示值為符號
例如:

let message = "some string";      
console.log(typeof message);     //   string
console.log(typeof (message));    //   string
console.log(95);     //    number

Undefined 類型##

Undefined數(shù)據(jù)類型只有一個值,即undefined。當(dāng)你使用了var或者let聲明了一個變量但沒有對其進(jìn)行初始化時,就相當(dāng)于給這個變量賦值了undefined:

let message;
console.log(message);     //undefined
console.log(message == undefined);     // true

默認(rèn)情況下,任何未經(jīng)過初始化的變量都會自動獲得undefined值
需要注意的是,對未初始化和未定義的變量調(diào)用typeof操作符,返回的值都是undefined:

let message
console.log(typeof message);    //   undefined
console.log(typeof age);     //   undefined

因此建議在聲明變量時一定要對其進(jìn)行初始化,只有這樣你才會知道當(dāng)返回undefined時,這是一個未聲明的變量,而不是沒有對其進(jìn)行初始化

常見返回undefined值的場景:

// 變量聲明了,但沒有賦值
var i;
i // undefined

// 調(diào)用函數(shù)時,應(yīng)該提供的參數(shù)沒有提供,該參數(shù)等于 undefined
function f(x) {
  return x;
}
f() // undefined

// 對象沒有賦值的屬性
var  o = new Object();
o.p // undefined

// 函數(shù)沒有返回值時,默認(rèn)返回 undefined
function f() {}
f() // undefined

Null 類型##

同樣,該類型只有一個值null。邏輯上講,null值表示一個空對象指針,所以當(dāng)對null調(diào)用typeof操作符時,返回的數(shù)據(jù)類型為object
任何時候,當(dāng)你定義一個對象,而又恰好沒有需要存入對象的數(shù)據(jù),那么請用null來暫時填補(bǔ)它
undefined是由null派生而來,因此ECMA-262將他們定義為表面上相等:

console.log(null == undefined);      //  true

然而即便是undefined和null有派生關(guān)系,但它們的用途卻完全不一樣,一般情況下我們不會主動給變量賦值為undefined。然而對于對象來講,用null來填充它有時候卻是相當(dāng)必要的

Boolean 類型##

這種數(shù)據(jù)類型只有兩個字面上的值:true 和 false
需要強(qiáng)調(diào)的是:這兩個布爾值是不等同于數(shù)字1和0的
雖然布爾值只有兩個,但是ECMAScript可以將其它數(shù)據(jù)類型轉(zhuǎn)換為布爾值,具體的轉(zhuǎn)換規(guī)則如下所示:
當(dāng)以下數(shù)據(jù)類型為如下值時,轉(zhuǎn)換為布爾值為true:
Boolean——true
String——非空字符串
Number——非零數(shù)值(包括無窮值)
Object——任意對象
Undefined——N/A(不存在)

當(dāng)以下數(shù)據(jù)類型為如下值時,轉(zhuǎn)換為布爾值為false:
Boolean——false
String——""(空字符串)
Number——0、NaN
Object——null
Undefined——undefined

這種轉(zhuǎn)換方式常用于if等流控制語句:

let message = "hello world !"
if(message){
  console.log("value is true.")
}

Number 類型##

八進(jìn)制、十進(jìn)制和十六進(jìn)制的表示方法:
十進(jìn)制是最基本的數(shù)值字面量,直接寫出來即可:

let intNum = 55;      // 十進(jìn)制整數(shù)

對于八進(jìn)制字面量而言,第一個數(shù)字必須是零(0),然后后面才是相應(yīng)的八進(jìn)制數(shù)字(0-7),如果字面量中包含了超出給定有效范圍的數(shù)值,或者前綴不是0,則會當(dāng)成普通的十進(jìn)制數(shù)來處理:

let octalNum1 = 070;    // 56(八進(jìn)制)
let octalNum2 = 079;   // 79(被當(dāng)成普通十進(jìn)制處理)
let octalNum3 = 08;    // 8 (同上)

需要注意的是,八進(jìn)制字面量在嚴(yán)格模式下是無效的,ES6中規(guī)定八進(jìn)制數(shù)的表示方法的前綴為0o,如:

let octalNum1 = 0o253;    // 171(八進(jìn)制)
let octalNum2 = 0o115;   // 77(同上)
let octalNum3 = 0o632;    // 410 (同上)

對于十六進(jìn)制字面量而言,前綴必須為0x,然后才是十六進(jìn)制數(shù)字(0-F),十六進(jìn)制中的字母大小寫均可,例如:

let hexNum1 = 0xA1;      //  161(十六進(jìn)制)
let hexNum2 = 0xfff;        // 4095(同上)

使用八進(jìn)制和十六進(jìn)制創(chuàng)建的數(shù)值在所有數(shù)學(xué)操作中都被視為十進(jìn)制數(shù)值

浮點值

若要定義浮點值,數(shù)值當(dāng)中必須包含有小數(shù)點,且小數(shù)點后面至少要有一個數(shù)字,雖然小數(shù)點前面的數(shù)字可有可無,但還是推薦加上:

let floatNum1 = 1.1;     //  1.1
let floatNum2 = 0.1;     //  0.1
let floatNum3 = .1;       //  0.1(不推薦)

因為浮點值的存儲空間會是整數(shù)值的兩倍,所以ECMAScript總是想辦法將值轉(zhuǎn)換為整數(shù),若小數(shù)點后面沒有數(shù)字,則會自動轉(zhuǎn)化為整數(shù)來處理;類似的,如果數(shù)值本身為整數(shù),只是小數(shù)點后面跟著0,也會被轉(zhuǎn)化為整數(shù)來處理:

let float1 = 1.;       //  小數(shù)點后面沒用數(shù)字,當(dāng)成整數(shù)1來處理
let float2 = 1.0;     //  本身是整數(shù)只是表示為小數(shù),也當(dāng)成整數(shù)來處理

科學(xué)計數(shù)法
如果要用科學(xué)計數(shù)法表示一個整數(shù),則要求是一個數(shù)值(整數(shù)或浮點值),后面跟一個大寫或者小寫的字母e,再加上一個要乘的10的多少次冪:

let num1 = 3.1275e7;     // 等于31275000

同理,科學(xué)計數(shù)法也可以用來表示數(shù)值很小的值:

let num2 = 123e-5;      // 等于0.00123

雖然浮點值精度最高可以達(dá)到17位小數(shù),但是在算數(shù)計算中遠(yuǎn)不如整數(shù)那么精確,比如:

0.1 + 0.2 ;    // 0.30000000000000004(答案不是0.3)

由于這種微小的舍入錯誤,導(dǎo)致實際操作時很難對浮點值進(jìn)行測試,比如:

let a = 0.1;
let b = 0.2;
if(a + b == 0.3){
   console.log('you got 0.3.');      //  這種測試是沒有任何意義的
}

因此我的建議是:永遠(yuǎn)不要測試某個特定的浮點值!
(注意:這種錯誤并非ECMAScript獨有,其它使用IEEE754數(shù)值的語言也都有這個問題)

數(shù)值的范圍:
由于內(nèi)存限制,ECMAScript并不能支持這個世界上所有的值,實際上,它所能表示的值有一個限制范圍:ECMAScript所能表示的最小值存儲在Number.MIN_VALUE中,這個值一般是5e-324;最大值保存在Number.MAX_VALUE中,這個值一般是1.7976931348623157e+308
如果某個計算值超出了JavaScript所能表示的范圍,那么這個值將會自動轉(zhuǎn)換為一個特殊的Infinity值,其中正無窮表示為Infinity,負(fù)無窮表示為-Infinity:

let res = Number.MAX_VALUE + Number.MAX_VALUE;
console.log(res);     // Infinity

NaN
這是一個特殊的數(shù)值,意為“不是數(shù)值(not a number)”,用于表示本來會返回數(shù)值的操作失敗了(并不是拋出錯誤)。比方說用0除其它任何數(shù)字在其它語言中通常會導(dǎo)致錯誤,以至于代碼無法運行,但是在ECMAScript中,0、+0或-0相除會返回NaN:

0 / 0 ;        //   NaN

若是非零數(shù)值除0,則會返回Infinity或-Infinity:

5 / 0 ;      // Infinity

NaN有幾個特殊的屬性:首先涉及NaN的操作始終都會返回NaN,其次NaN不等于包含NaN在內(nèi)的任何值,比如:

NaN == NaN;   //  false

ECMAScript提供了一個isNaN()函數(shù),該函數(shù)可以接受一個參數(shù),可以使任意數(shù)據(jù)類型,然后來判斷這個參數(shù)是否是“不是數(shù)值”。參數(shù)在傳入isNaN()函數(shù)后,該函數(shù)會嘗試將它轉(zhuǎn)換為數(shù)值。任何不能轉(zhuǎn)換為數(shù)值的參數(shù)都會導(dǎo)致這個函數(shù)返回true,比如:

console.log(isNaN(NaN));      // true
console.log(isNaN(10));       //  false
console.log(isNaN('10'));      //  false,可以轉(zhuǎn)換為數(shù)值10
console.log(isNaN('age'));      //  true
console.log(isNaN(true));      //   false,可以轉(zhuǎn)換為數(shù)值1

數(shù)值轉(zhuǎn)換:
有三個函數(shù)可以將非數(shù)值轉(zhuǎn)換為數(shù)值:Number()、parseInt()、parseFloat()
Number()函數(shù)的轉(zhuǎn)換基于以下規(guī)則:

  • 布爾值:true轉(zhuǎn)換為1,false轉(zhuǎn)換為0
  • 數(shù)值:直接返回
  • null:返回為0
  • undefined:返回為NaN
  • 字符串:應(yīng)用以下規(guī)則:
    -- 如果字符串包含數(shù)字字符,包括數(shù)字字符前帶有加、減號的情況,則轉(zhuǎn)換為一個十進(jìn)制數(shù)值(忽略前面的0)
    -- 如果字符串包含有效的浮點值格式,則轉(zhuǎn)換為相應(yīng)的浮點值(忽略前面的0)
    -- 如果字符串包含有效的十六進(jìn)制格式,如0xff,則會轉(zhuǎn)換為與之對應(yīng)的十進(jìn)制數(shù)值
    -- 如果是空字符串,返回0
    -- 如果字符串包含除上述情況以外的其它字符,返回NaN
    舉例:
Number('hello world 123');    // NaN
Number('');                            // 0
Number('000000111');          // 111
Number(true)                       // 1

考慮到Number()函數(shù)轉(zhuǎn)換字符串時相對復(fù)雜并且反常規(guī),大多數(shù)時候我們都用parseInt()來得到整數(shù)
首先字符串前面的空格會被忽略,從第一個非空格字符開始,如果不是數(shù)值字符或者加減號,則立即返回NaN;如果第一個字符是數(shù)值字符或者加減號,則會繼續(xù)以此檢測每個字符,直到字符串末尾,或碰到非數(shù)字字符:

parseInt('      000245688aaadsdf');     //   245688(前面空格和0被完美的忽略掉了)
parseInt('3.14159');      // 3(小數(shù)點為非數(shù)字字符,其后的數(shù)字也被忽略掉)
parseInt('');       // NaN
parseInt('0xff');      // 255(十六進(jìn)制會被轉(zhuǎn)換為十進(jìn)制)

parseInt()接受第二個參數(shù),用來指定底數(shù)進(jìn)行解析轉(zhuǎn)化:

parseInt('100',2);     // 4(按二進(jìn)制解析)
parseInt('100',8);     // 64(按八進(jìn)制解析)
parseInt('100',10);     // 100(按十進(jìn)制解析)
parseInt('100',16);     // 256(按十六進(jìn)制解析)

因為如果不傳入底數(shù)就相當(dāng)于讓parseInt()函數(shù)自己解析,因此為了避免出錯,建議始終傳入第二個參數(shù)

parseFloat()函數(shù)的工作方式與parseInt()函數(shù)類似,都是從頭開始檢測字符,直到字符串末尾。相比于parseInt()的唯一區(qū)別就是其只能解析十進(jìn)制數(shù)值,因此無法傳入第二個參數(shù):

parseFloat('   0005646.7859aposdaj');     //5646.7859(始終忽略字符串開頭的0)
parseFloat('    000.25456');     //0.25456(小數(shù)點前面的0會保留)
parseFloat('005.6846.456899');         //5.6846(只保留最左邊小數(shù)點的小數(shù))
parseFloat('');        //NaN
parseFloat('3.14e12')        //3140000000000(適用于科學(xué)計數(shù)法)
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容