JavaScript數(shù)據(jù)類型及相互間的轉(zhuǎn)換規(guī)則
數(shù)據(jù)類型的分類
JS中的數(shù)據(jù)類型有七中原始數(shù)據(jù)類型:
- 原始數(shù)據(jù)類型[值類型/基本數(shù)據(jù)類型]:
- number 數(shù)字
- string 字符串
- boolean 布爾
- null 空對象指針
- undefined 未定義
- symbol 唯一值
- bigint 大數(shù)
- 對象類型[引用數(shù)據(jù)類型]
- object
- 標(biāo)準(zhǔn)普通對象 object
- 標(biāo)準(zhǔn)特殊對象 Array、RegExp、Date、Math、Error...
- 非標(biāo)準(zhǔn)特殊對象 Number、String、Boolean...
- 可調(diào)用/執(zhí)行對象 函數(shù)Function
- object
非標(biāo)準(zhǔn)特殊對象
除了null和undefined每個(gè)原始值類型都有一個(gè)自己對應(yīng)的對象類型值
Symbol
Symbol是唯一值,他是不能通過New操作符進(jìn)行創(chuàng)建的,每次執(zhí)行Symbol都是創(chuàng)建一個(gè)唯一值,下方代碼A和B雖然看起來是一樣的但卻不相等的兩個(gè)值。假如如果把C=A這樣把A的值賦給C,那么A和C肯定是相等的
let A = Symbol('i東東') let B = Symbol('i東東') let C = A console.log(A === B); // false console.log(A === C); // true
應(yīng)用場景:
- 給對象設(shè)置唯一值的屬性名,在ES6之前對象的屬性名只能是字符串類型,但是新增了ES6之后對象的屬性名增加了可以用Symbol類型的屬性名。
- Map新的數(shù)據(jù)結(jié)構(gòu):可以允許屬性名是對象
- Symbol.asyncIterator/iterator/hasInstance/toStringTag...是某些JS知識底層實(shí)現(xiàn)機(jī)制
- 在派發(fā)行為標(biāo)識進(jìn)行統(tǒng)一管理的時(shí)候,可以基于Symbol類型的值,保證標(biāo)識的唯一性
用字符串和數(shù)字類型的都可以取到值,name就可以認(rèn)為他們的屬性名是字符串類型的
下方代碼console.log([Symbol('AA')])
是無法取到值的,因?yàn)檫@個(gè)相當(dāng)于創(chuàng)建了一個(gè)新的唯一值,用新的唯一值去訪問是不對應(yīng)的,正確的方法應(yīng)該是創(chuàng)建一個(gè)唯一值,再把這個(gè)唯一值作為屬性去訪問。
let key = Symbol('88') let obj = { num: 100, 10:'數(shù)字', [Symbol('AA')]:'Symbol類型的屬性名', // 在大括號中加Symbol語法要求必須加大括號 [key]:400 } console.log(obj[Symbol('AA')]); // undefined console.log(obj[key]); // 400說
一個(gè)對象的屬性名是不能重復(fù)的,用唯一值做屬性的好處就是,他是不會重復(fù)的
let obj = { [Symbol('AA')]: 100, [Symbol('AA')]: 100, // 這兩個(gè)是不同的兩個(gè)值 }
BigInt 大數(shù)類型
JS中的最大安全數(shù) Number.MAX_SAFE_INTEGER = 9007199254740991
JS中的最小安全數(shù) Number.MIN_SAFE_INTEGER = -9007199254740991
超過安全數(shù)后,進(jìn)行運(yùn)算或者訪問,結(jié)果會不準(zhǔn)確?。?/strong> 數(shù)據(jù)庫當(dāng)中存取數(shù)據(jù)會分成整型、長整型、短整型,長整型支持的數(shù)字長度是比JS的安全數(shù)大的,當(dāng)服務(wù)器返回給客戶端一個(gè)長整型的數(shù)字,如果超出最大安全數(shù)值就會出現(xiàn)問題。
解決方案:
- 服務(wù)器端給客戶端返回大數(shù),按照字符串格式返回!
- 客戶端把其變換成 Bigint
- 最后把運(yùn)算后的BigInt轉(zhuǎn)換為字符串,再傳遞給服務(wù)器
console.log(BigInt('9007199254740991') + BigInt(12345)); // 9007199254753336n console.log(9007199254753336n.toString()); // 9007199254753336 // 123n 在數(shù)字后面直接加`n`也表示大數(shù)BigInt
數(shù)據(jù)類型檢測
- typeof
- instanceof
- constryctor
- Object.prototype.toString.call
- Array.isArray
- isNaN
在日常開發(fā)中用到最多的就是typeof檢測數(shù)據(jù)類型,所有的數(shù)據(jù)類型值,在計(jì)算機(jī)底層都是按照'64位'的二進(jìn)制進(jìn)行存儲的!type是按照二進(jìn)制值進(jìn)行檢測類型的
例如:
- 二進(jìn)制的前三位是0,認(rèn)為是對象,然后再去看有沒有實(shí)現(xiàn)call方法,如果實(shí)現(xiàn)了返回'functhon',沒有時(shí)間,則返回'object'
- 第一位是1為整數(shù)
- 010浮點(diǎn)數(shù)
- 100字符串
- 110布爾
- 000000... null(null為64個(gè)0) ==> object [因?yàn)閠ypeof的局限性]
- ......
檢測未被申明的變量,值為undefined
console.log(a); // ReferenceError: a is not defined console.log(typeof a); // undefined
場景1:檢測當(dāng)前值是否是一個(gè)對象
const fn = options =>{ let type = typeof options if(options !== null && (type === 'object' || type === 'function')){ // 這樣進(jìn)來的才能確保是一個(gè)對象 } } fn({ num:10 })
場景2:支持更多的模塊導(dǎo)入方案
(function(){ if(typeof window !== 'undefined') window.utils = utils if(typeof module === 'object' && typeof module.exports == 'object') module.exports = utils })()
數(shù)據(jù)類型間的相互轉(zhuǎn)換
數(shù)據(jù)類型間的相互轉(zhuǎn)換主要有隱式數(shù)據(jù)類型轉(zhuǎn)換和顯示數(shù)據(jù)類型轉(zhuǎn)換兩種。 一般用于瀏覽器中的隱式轉(zhuǎn)換:
- 數(shù)學(xué)運(yùn)算
- isNaN檢測
- == 比較
比如說在數(shù)據(jù)運(yùn)算時(shí)會進(jìn)行隱式數(shù)據(jù)類型轉(zhuǎn)換,10-2的時(shí)候?qū)嶋H上默認(rèn)就調(diào)用了Number('2')進(jìn)行了類型轉(zhuǎn)換之后才進(jìn)行的減法運(yùn)算。
比如用isNaN來判斷時(shí)前值是不是一個(gè)有效數(shù)字,就相當(dāng)于調(diào)用了下面的方法,先調(diào)用Number再執(zhí)行isNaN。
規(guī)則
Number([val])
- 字符串轉(zhuǎn)換為數(shù)字:空字符串變?yōu)?,如果出現(xiàn)任何非有效數(shù)字字符都是NaN
- 把布爾值轉(zhuǎn)換成數(shù)字:true=>1 false=>0
- null=>0 undefined=>NaN
- Symbol無法轉(zhuǎn)換為數(shù)字,會報(bào)錯(cuò):Cannot convert a Symbol value to a number
- BigInt去除'n'(超出安全數(shù)字的會按照科學(xué)計(jì)數(shù)法處理)
- 那對象轉(zhuǎn)換為數(shù)字:先調(diào)用對象的
Symbol.toPrimitive
方法,如果不存在這個(gè)方法,再調(diào)用valueOf
獲取原始值,如果獲取的值不是原始值,在調(diào)用toString
把其變?yōu)樽址詈笞园涟炎址眠^Number
方法進(jìn)行轉(zhuǎn)換
let time = new Date() console.log(Number(time)); // 1662715039452 console.log(time[Symbol.toPrimitive]('number')); // 1662715039452 // 首先檢測 Symbol.toPrimitive有沒有, 結(jié)果:有 而且是一個(gè)函數(shù) time[Symbol.toPrimitive]('number')
let arr = [10] console.log(Number(arr)); /** * 首先arr[Symbol.toPrimitive] => undefined * 然后arr.valueOf() 數(shù)組是沒有原始值的 => [10] 任何一個(gè)對象都有valueOf * 再然后 arr.toString => '10' * 最后在把字符串'10'轉(zhuǎn)換為數(shù)字 => 10 */
let num = new Number(10) console.log(Number(num)); /** * 首先num[Symbol.toPrimitive] => undefined * 然后num.valueOf() 數(shù)組是沒有原始值的 => 10 */
parseInt([val],[radix]) parseFloat([val])
parseInt([val],[radix])是可以傳兩個(gè)值進(jìn)去的:
- value必須是字符串,不是字符串會會先隱式轉(zhuǎn)換成字符串,通過String([val]),如果是對象會用上面的三步進(jìn)行轉(zhuǎn)換
- radix進(jìn)制,如果不寫或者寫0,則默認(rèn)為10進(jìn)制,如果字符串是以0x開始的,默認(rèn)為16進(jìn)制,有效進(jìn)制范圍2~36之間(如果不在這個(gè)區(qū)間結(jié)果直接是NaN)。從[val]字符串左側(cè)開始第一個(gè)字符開始查找,查找出符合[radix]進(jìn)制的值(遇到不符合的則結(jié)束查找,無論后面是否還有有符合的),把找到的內(nèi)容按照[radix]進(jìn)制,轉(zhuǎn)化為10進(jìn)制??!
console.log(parseInt('10103px13',2)); // 10 /** * 首先找到符合二進(jìn)制的數(shù) '1010' * 把這個(gè)二進(jìn)制值轉(zhuǎn)換為十進(jìn)制 '按權(quán)展開求和' * 1*2^3+0*2^2+1*2^1+0*2^0 => 8+0+2+2 => 10 */
這里放一道字節(jié)面試題
arr會輸出什么,為什么? let arr = [27.2,0,'0013','14px',123] arr = arr.map(parseInt)
解題步驟:
- arr.map方法:迭代數(shù)組中的每一項(xiàng),并且把每一項(xiàng)進(jìn)行修改,原始數(shù)組不變,以新數(shù)組的形式返回。迭代數(shù)組中的每一項(xiàng)item為當(dāng)前值,index為索引。
- map中應(yīng)該接受一個(gè)函數(shù),現(xiàn)在我們是把
parseInt
作為這個(gè)函數(shù)傳遞進(jìn)去了,所以每次迭代都會執(zhí)行parseInt
并且將item和index作為參數(shù)傳遞進(jìn)去
/** * parseInt(27.2,0) => 找符合二進(jìn)制的'27',當(dāng)做十進(jìn)制轉(zhuǎn)成十進(jìn)制=> 27 * parseInt(0,1) => 超出有效進(jìn)制范圍 => NaN * parseInt('0013',2) => 001 當(dāng)做二進(jìn)制轉(zhuǎn)化為十進(jìn)制 => 0+0+1 => 1 * parseInt('14px',3) => 1 當(dāng)做三進(jìn)制轉(zhuǎn)成十進(jìn)制 => 1 * parseInt(123,4) => parseInt('123',4) => 123當(dāng)做四進(jìn)制轉(zhuǎn)成十進(jìn)制 1*4^2+2*4^1+3*4^0 => 16+8+4 => 27 */
所以最終得:arr = [27, NaN, 1, 1, 27]
注:
parseInt('0013',2) => 001 當(dāng)做二進(jìn)制轉(zhuǎn)化為十進(jìn)制 => 0+0+1 => 1 parseInt(0013,2) => 0013 當(dāng)js中遇到以0開頭的數(shù)字會默認(rèn)當(dāng)做8進(jìn)制轉(zhuǎn)為10進(jìn)制然后在進(jìn)行其他運(yùn)算 => 當(dāng)做八進(jìn)制轉(zhuǎn)為十進(jìn)制 0*8^3+0*8^2+1*8^1+3*8^0 => 11 => 二進(jìn)制轉(zhuǎn)十進(jìn)制 11 2+1=3
把其他類型轉(zhuǎn)換為String
轉(zhuǎn)換規(guī)則:
- '+'出現(xiàn)左右兩邊,其中一邊是字符串,或者是某些對象,會以字符串拼接的規(guī)則處理
- '+'出現(xiàn)在一個(gè)值的左邊,轉(zhuǎn)換為數(shù)字
console.log(10 + '10'); // 1010 console.log(10 + new Number(10)); // new Number(10)[Symbol.toPrimitive] -> undefined // new Number(10).valueOf() => 10 // 10 + 10 = 20 console.log(10 + new Date()); // new Date()[Symbol.toPrimitive]('default') -> 不知道傳遞什么會傳defaulu => 'Tue Sep 13 2022 17:00:40 GMT+0800 (中國標(biāo)準(zhǔn)時(shí)間)' // 最終等于:10'Tue Sep 13 2022 17:00:40 GMT+0800 (中國標(biāo)準(zhǔn)時(shí)間)' console.log(10 + [10]); // [10][Symbol.toPrimitive] -> undefined // [10].valueOf => '[10]' // [10].toString() => '10' // 最終等于: '1010' let num = '10' console.log(+num) // 10 轉(zhuǎn)換為數(shù)字
把其他類型的值轉(zhuǎn)換成Boolean
Boolean(0) = false 除了0 NaN undefined 空字符串 null 以外都是true
==兩個(gè)等號比較規(guī)則
- ==相等,兩邊數(shù)據(jù)類型不同,首先要轉(zhuǎn)換為相同類型,然后在進(jìn)行比較
- 對象==字符串 對象轉(zhuǎn)字符串[Symbol.toPrimitive]->valueOf()->toString()
- null == nudefined -> true null/undefined和其他任何值都不相等
- null === undefined -> false
- 對象==對象 比較的是堆內(nèi)存地址,地址相同則相等
- NaN !== NaN
- 除了以上情況,只要兩邊類型不一致,剩下的都是轉(zhuǎn)換為數(shù)字,然后在進(jìn)行比較的,'==='絕對相等,如果兩邊類型不同則直接是false,不會轉(zhuǎn)換數(shù)據(jù)類型。
NaN == NaN // false NaN永遠(yuǎn)不可能等于NaN console.log(Object.is(NaN,NaN)); // true
貼一道面試題 下面輸出為什么?
console.log([]==false); // 首先都會轉(zhuǎn)換為數(shù)字, 0 == 0 => true console.log(![]==false); // 先處理![]=>false == false =>true
Js中的裝箱和拆箱
裝箱和拆箱都是瀏覽器進(jìn)行數(shù)據(jù)類型隱式轉(zhuǎn)換的過程
let num = 10 console.log(num.toFixed(2)); // 10.00 // num是原始值,不是對象,按常理來講是不能做'成員訪問'的 // 默認(rèn)會做裝箱操作: new Number(num) 變?yōu)榉菢?biāo)準(zhǔn)鐵樹對象,這樣就可以調(diào)用toFixed了 let num = new Number(10) console.log(num + 10); // 20 // 在操作的過程中瀏覽器會將num這個(gè)非標(biāo)準(zhǔn)特殊對象變?yōu)樵贾? [Symbol.toPrimitive] -> valueOf -> toString 這個(gè)操作叫做拆箱 // 裝箱和拆箱都是瀏覽器進(jìn)行數(shù)據(jù)類型隱式轉(zhuǎn)換的過程
到此這篇關(guān)于JavaScript數(shù)據(jù)類型及相互間的轉(zhuǎn)換規(guī)則的文章就介紹到這了,更多相關(guān)JavaScript數(shù)據(jù)類型內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Javascript 兩個(gè)窗體之間傳值實(shí)現(xiàn)代碼
眾所周知window.open() 函數(shù)可以用來打開一個(gè)新窗口,那么如何在子窗體中向父窗體傳值呢,其實(shí)通過window.opener即可獲取父窗體的引用。2009-09-09微信小程序使用webview打開pdf文檔以及顯示網(wǎng)頁內(nèi)容的方法步驟
在線查看PDF文件,已經(jīng)是很常見的需求了,下面這篇文章主要給大家介紹了關(guān)于微信小程序使用webview打開pdf文檔以及顯示網(wǎng)頁內(nèi)容的方法步驟,文中通過圖文介紹的非常詳細(xì),需要的朋友可以參考下2022-07-07JS實(shí)現(xiàn)數(shù)組簡單去重及數(shù)組根據(jù)對象中的元素去重操作示例
這篇文章主要介紹了JS實(shí)現(xiàn)數(shù)組簡單去重及數(shù)組根據(jù)對象中的元素去重操作,涉及javascript數(shù)組元素的遍歷、判斷、追加等操作實(shí)現(xiàn)去重功能的相關(guān)技巧,需要的朋友可以參考下2018-01-01setTimeout與setInterval的區(qū)別淺析
這篇文章主要給大家介紹了關(guān)于setTimeout與setInterval區(qū)別的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家學(xué)習(xí)或者使用js具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧2019-03-03用javascript修復(fù)瀏覽器中頭痛問題的方法整理篇[譯]
我們提倡無論何時(shí)都盡可能地使用CSS,這樣我們更容易取得成功.現(xiàn)在瀏覽器對CSS的支持已經(jīng)非常好,肯定足以讓你用來控制你的網(wǎng)頁布局與排版.但,即使如此,還是有某些頁面元素會在不同的瀏覽器下表現(xiàn)也不一樣.2008-11-11Javascript頁面跳轉(zhuǎn)常見實(shí)現(xiàn)方式匯總
這篇文章主要介紹了Javascript頁面跳轉(zhuǎn)常見實(shí)現(xiàn)方式,結(jié)合實(shí)例匯總分析了JavaScript常用的七種頁面跳轉(zhuǎn)實(shí)現(xiàn)技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下2015-11-11document.documentElement && document.documentElement
document.documentElement && document.documentElement.scrollTop...2007-12-12js保留兩位小數(shù)最簡單的實(shí)現(xiàn)方法
JS數(shù)據(jù)格式化是在進(jìn)行web前端開發(fā)時(shí)常碰到的事情,特別是在數(shù)據(jù)類型為Float的數(shù)據(jù)就需要特殊處理,如保留兩位小數(shù)、小數(shù)點(diǎn)后的數(shù)據(jù)是否需要四舍五入等等,下面這篇文章主要給大家介紹了關(guān)于js保留兩位小數(shù)最簡單的實(shí)現(xiàn)方法,需要的朋友可以參考下2023-05-05