一文詳解JavaScript有那些數(shù)據(jù)類(lèi)型
這同樣是一道面試中常見(jiàn)的問(wèn)題。
JS有8種數(shù)據(jù)類(lèi)型,分別是:
- Null
- Undefined
- Boolean
- Number
- BigInt
- String
- Symbol
- Object
1. Null
Null表示變量定義了但值為空。Null類(lèi)型只有一個(gè)null值,null是一個(gè)關(guān)鍵字,大小寫(xiě)敏感,一般對(duì)象和數(shù)組可以初始化為null。
2. Undefined
Undefined表示變量未定義。Undefined類(lèi)型只有一個(gè)undefined值,undefined是一個(gè)全局變量。我們可以通過(guò)window.hasOwnProperty方法確定一個(gè)變量是不是全局變量,如下:
window.hasOwnProperty(undefined) // true window.hasOwnProperty(null) // false
可以確定undefined確實(shí)是一個(gè)全局變量,而null不是。
既然undefined是一個(gè)全局變量,我們是不是可以更改undefined的值呢?在控制臺(tái)嘗試
window.undefined = 1 window.undefined // undefined
可以看出來(lái)undefined并不能修改,這是為什么呢?我們猜測(cè)undefined作為window的屬性,應(yīng)該是不可修改的,我們用Object.getOwnPropertyDescriptor方法獲取undefined屬性的屬性描述:
Object.getOwnPropertyDescriptor(window, 'undefined')
// 輸出
{
configurable: false
enumerable: false
value: undefined
writable: false
}可以看出writable的值是false,表示該屬性不可被更改
3. Boolean
Boolean類(lèi)型表示一個(gè)邏輯實(shí)體,有兩個(gè)值true和false。一般用于條件判斷種,三元運(yùn)算符(?:)、if、while、for中
4. Number
Number類(lèi)型表示數(shù)字。我們可以通過(guò)Number.MAX_VALUE和Number.MIN_VALUE分別得到Number的最大和最小值:
Number.MAX_VALUE // 1.7976931348623157e+308 Number.MIN_VALUE // 5e-324
可以看出Number類(lèi)型可以表示的值的范圍是非常大,我們?nèi)粘J褂脦缀醪粫?huì)用到這么大的數(shù)。不過(guò)這里有個(gè)問(wèn)題,雖然可以表示這么大的數(shù),但是我們可以看出有效位數(shù)是小數(shù)點(diǎn)后16位,在加整數(shù)位一共是17位,就是千萬(wàn)億級(jí)別可以精確表示,再大后面就省略為0了,只有級(jí)別增加。所以要精確表示數(shù)字,我們得將數(shù)字的計(jì)算范圍控制再安全邊界以?xún)?nèi),js給出了2個(gè)安全邊界:
Number.MAX_SAFE_INTEGER // 9007199254740991 即 2^53 – 1 Number.MIN_SAFE_INTEGER // -9007199254740991 即 -(2^53 - 1)
為什么是這兩個(gè)數(shù)呢,因?yàn)殡p精度浮點(diǎn)格式只有 52 位用于表示尾數(shù),因此它只能安全地表示介于 -(2^53 – 1) 和 2^53 – 1 之間的整數(shù)。
這里就引出JS中Number的編碼格式:
IEEE 754 雙精度浮點(diǎn)數(shù)使用 64 位來(lái)表示 3 個(gè)部分:
- 1 位用于表示符號(hào)(sign)(正數(shù)或者負(fù)數(shù))
- 11 位用于表示指數(shù)(exponent)(-1022 到 1023)
- 52 位用于表示尾數(shù)(mantissa)(表示 0 和 1 之間的數(shù)值)
尾數(shù)(也稱(chēng)為有效數(shù))是表示實(shí)際值(有效數(shù)字)的數(shù)值部分。指數(shù)是尾數(shù)應(yīng)乘以的 2 的冪次。將其視為科學(xué)計(jì)數(shù)法:
Number=(−1)sign⋅(1+mantissa)⋅2exponent
尾數(shù)使用 52 比特存儲(chǔ),在二進(jìn)制小數(shù)中解釋為
1.…之后的數(shù)字。
2^53表示成2進(jìn)制是1后面53個(gè)0,需要54位來(lái)表示;而2^53-1表示成2進(jìn)制是1后面52個(gè)1,我們?cè)诳刂婆_(tái)驗(yàn)證:
Number.MAX_SAFE_INTEGER.toString(2) // 2^53-1 // 輸出:'11111111111111111111111111111111111111111111111111111' Number.MAX_SAFE_INTEGER.toString(2).length // 輸出:53 (Number.MAX_SAFE_INTEGER+1).toString(2) // 2^53 // 輸出:'100000000000000000000000000000000000000000000000000000' (Number.MAX_SAFE_INTEGER+1).toString(2).length // 輸出:54
可以看出,2^53-1是可以用53位精確表示的,而2^53卻需要54位來(lái)精確表示,只是后面全是0還可以用52位尾數(shù)和指數(shù)精確表示,若+1,最后的尾數(shù)就被省略了,也就是說(shuō)這個(gè)編碼最多可以精確表示到2^53,這滿(mǎn)足安全數(shù)+1也必須精確表示的定義,所以最大安全數(shù)就是2^53-1。
那么我們考慮一下小數(shù)的加法運(yùn)算
0.1+0.2===0.3 // 這個(gè)成立嗎?答案是false
0.1.toString(2)
// 輸出:'0.0001100110011001100110011001100110011001100110011001101'
0.2.toString(2)
// 輸出:'0.001100110011001100110011001100110011001100110011001101'
0.0001100110011001100110011001100110011001100110011001101 +
0.001100110011001100110011001100110011001100110011001101 =
0.0100110011001100110011001100110011001100110011001100111
// 計(jì)算小數(shù)位
binFrac = '0100110011001100110011001100110011001100110011001100111'
let value = 0;
for (let i = 0; i < binFrac.length; i++) {
if (binFrac[i] === '1') {
value += 2 ** (-(i + 1)); // 第 i 位對(duì)應(yīng) 2^(-(i+1))
}
}
value
// 輸出 0.30000000000000004由于二進(jìn)制小數(shù)的精度,使得0.1+0.2時(shí)沒(méi)有得到準(zhǔn)確的0.3,0.1和0.2都是循環(huán)小數(shù)。是不是所有小數(shù)加法都這樣呢?并不是,只有當(dāng)兩個(gè)操作數(shù)及其運(yùn)算結(jié)果都能表示為 有限二進(jìn)制小數(shù)(即分母為 2 的冪)時(shí),加法才是精確的。例如 0.5 + 0.25 = 0.75 是精確的,因?yàn)?nbsp;0.5 = 1/2, 0.25 = 1/4, 0.75 = 3/4,分母均為 2 的冪。而為了使得小數(shù)計(jì)算準(zhǔn)確,我們應(yīng)該排除最后的那個(gè)小數(shù)位,JS有一個(gè)Number.EPSILON表示1 與大于 1 的最小浮點(diǎn)數(shù)之間的差值,值為2^-52,此時(shí)我們可以這么比較0.1+0.2和0.3的值
0.1+0.2 -0.3 < Number.EPSILON // true Math.abs(0.1+0.2 -0.3).toString(2) // 輸出:'0.000000000000000000000000000000000000000000000000000001' Number.EPSILON.toString(2) // 輸出:'0.0000000000000000000000000000000000000000000000000001' (0.1+0.2).toString(2) // 輸出:'0.0100110011001100110011001100110011001100110011001101' 0.3.toString(2) // 輸出:'0.010011001100110011001100110011001100110011001100110011'
5. BigInt
BigInt可以表示比2^53-1更大的整數(shù),可以表示任意大的整數(shù)。寫(xiě)法上在整數(shù)后面加n即可得到一個(gè)BigInt,或者使用BigInt函數(shù),如下:
const big1 = 9007199254740991n; const big2 = BigInt(9007199254740991);
它與Nubmer的區(qū)別在于,不能使用Math對(duì)象中的方法,不能和Number類(lèi)型的值直接做運(yùn)算
1n+1 // 報(bào)錯(cuò)Uncaught TypeError: Cannot mix BigInt and other types, // use explicit conversions Number(1n)+1 // 輸出2 BigInt(1) + 1n // 輸出2n Math.abs(-1n) // 報(bào)錯(cuò)Uncaught TypeError: Cannot convert a BigInt value to a number
BigInt 不能參與 JSON 序列化(JSON.stringify(1n)會(huì)報(bào)錯(cuò))。
6. String
String類(lèi)型用于保存文本數(shù)據(jù)。字符串基本上表示為的 UTF-16 碼元序列。在 UTF-16 編碼中,每個(gè)碼元都是 16 位長(zhǎng)。那么String類(lèi)型有最大長(zhǎng)度限制嗎?ECMAScript 規(guī)范規(guī)定字符串長(zhǎng)度必須≤ 2^53 - 1 ,因?yàn)?nbsp;.length 和索引訪問(wèn)(如charAt、[i])依賴(lài)于可精確表示的整數(shù)。但實(shí)際引擎(如 V8)出于性能考慮,通常限制為 2^30 - 1(約 10 億)。”我們可以在控制臺(tái)驗(yàn)證:
const a = new Array(2**32) // 報(bào)錯(cuò):Uncaught RangeError: Invalid array length const a = new Array(2**32-1) // 正常
7. Symbol
Symbol是一種唯一并且不可變的原始值。每個(gè)從 Symbol() 返回的 symbol 值都是唯一的。一個(gè) symbol 值能作為對(duì)象屬性的標(biāo)識(shí)符;這是該數(shù)據(jù)類(lèi)型僅有的目的。
const symbol1 = Symbol('a');
console.log(symbol1) // 輸出:Symbol(a)8. Object
對(duì)象可以被看作是一個(gè)屬性的集合。對(duì)象屬性等價(jià)于鍵值對(duì)。屬性鍵要么是字符串,要么是 symbol。當(dāng)其他類(lèi)型(如數(shù)字)用于索引對(duì)象時(shí),值會(huì)隱式地轉(zhuǎn)化為字符串。屬性值可以是任何類(lèi)型的值,包括其他對(duì)象,從而可以構(gòu)建復(fù)雜的數(shù)據(jù)結(jié)構(gòu)。
有兩種類(lèi)型的對(duì)象屬性:數(shù)據(jù)屬性和訪問(wèn)器屬性。每個(gè)屬性都有對(duì)應(yīng)的特性。可以通過(guò)Object.defineProperty()設(shè)置屬性特性,或通過(guò)Object.getOwnPropertyDescriptor()獲取屬性特性。
數(shù)據(jù)屬性的特性有:
value: 通過(guò)屬性的get獲取到的值
writable:布爾值,表示屬性是否可以通過(guò)賦值進(jìn)行修改。
enumerable:布爾值,是否可以通過(guò)for...in循環(huán)枚舉
configurable:布爾值,表示屬性是否可以刪除,是否可以更改為訪問(wèn)器屬性,以及是否可以更改其特性。
訪問(wèn)器屬性:
get: 當(dāng)執(zhí)行值的 get 訪問(wèn)時(shí),使用一個(gè)空的參數(shù)列表調(diào)用函數(shù)獲取屬性值。
set: 使用包含賦予的值的參數(shù)調(diào)用函數(shù)。每當(dāng)嘗試更改指定屬性時(shí)執(zhí)行。
enumerable和configurable與上面一樣。
在Object上有很多復(fù)雜的東西,關(guān)于對(duì)象的原型鏈、屬性描述符、Proxy 等高級(jí)特性,我們將在后續(xù)文章中深入探討。。
總結(jié)
到此這篇關(guān)于JavaScript有那些數(shù)據(jù)類(lèi)型的文章就介紹到這了,更多相關(guān)JS數(shù)據(jù)類(lèi)型內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
JavaScript判斷訪問(wèn)的來(lái)源是手機(jī)還是電腦,用的哪種瀏覽器
這篇文章主要介紹了使用JavaScript判斷訪問(wèn)的來(lái)源是手機(jī)還是電腦,用的哪種瀏覽器。需要的朋友可以過(guò)來(lái)參考下,希望對(duì)大家有所幫助2013-12-12
解讀請(qǐng)求方式Method和請(qǐng)求類(lèi)型Content-Type
HTTP請(qǐng)求中,Content-Type頭部用于指定請(qǐng)求體或響應(yīng)體的類(lèi)型,常見(jiàn)的有application/x-www-form-urlencoded、multipart/form-data、application/json、text/plain、application/xml等,常用請(qǐng)求方式包括Get、Post、Put、Delete2024-09-09
js點(diǎn)擊按鈕實(shí)現(xiàn)水波紋效果代碼(CSS3和Canves)
這篇文章主要為大家詳細(xì)介紹了點(diǎn)擊按鈕實(shí)現(xiàn)水波紋效果,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-09-09
JavaScript錯(cuò)誤處理:Uncaught (in promise) error的原因
本文詳細(xì)解釋了Uncaught(inpromise)錯(cuò)誤的原因、常見(jiàn)場(chǎng)景、處理方法以及如何系統(tǒng)性地防止這一錯(cuò)誤,同時(shí)提供了一些快速診斷和修復(fù)的技巧,需要的朋友可以參考下2026-02-02
mock.js模擬數(shù)據(jù)實(shí)現(xiàn)前后端分離
這篇文章主要為大家詳細(xì)介紹了mock.js模擬數(shù)據(jù)實(shí)現(xiàn)前后端分離,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-07-07
三種動(dòng)態(tài)加載js的jquery實(shí)例代碼另附去除js方法
這篇文章主要介紹了三種動(dòng)態(tài)加載js的jquery實(shí)例代碼另附去除js方法,需要的朋友可以參考下2014-04-04
JS加密插件CryptoJS實(shí)現(xiàn)AES加密操作示例
這篇文章主要介紹了JS加密插件CryptoJS實(shí)現(xiàn)AES加密操作,結(jié)合實(shí)例形式分析了CryptoJS插件的具體設(shè)置與AES加密操作實(shí)現(xiàn)技巧,需要的朋友可以參考下2018-08-08

