js數(shù)據(jù)類(lèi)型檢測(cè)和數(shù)據(jù)類(lèi)型轉(zhuǎn)換

1. 數(shù)據(jù)類(lèi)型概念

JavaScript 的數(shù)據(jù)類(lèi)型有下圖所示的 8 種:

其中吹害,前 7 種類(lèi)型為基礎(chǔ)類(lèi)型,最后 1 種(Object)為引用類(lèi)型,而引用數(shù)據(jù)類(lèi)型(Object)又分為圖上這幾種常見(jiàn)的類(lèi)型:Array - 數(shù)組對(duì)象RegExp - 正則對(duì)象Date - 日期對(duì)象劲够、Math - 數(shù)學(xué)函數(shù)震桶、Function - 函數(shù)對(duì)象

  1. 基礎(chǔ)類(lèi)型存儲(chǔ)在棧內(nèi)存,被引用或拷貝時(shí)征绎,會(huì)創(chuàng)建一個(gè)完全相等的變量蹲姐;
  2. 引用類(lèi)型存儲(chǔ)在堆內(nèi)存,存儲(chǔ)的是地址人柿,多個(gè)引用指向同一個(gè)地址

2. 數(shù)據(jù)類(lèi)型檢測(cè)常用的三種方法

2.1 typeof

typeof 1 // 'number'
typeof '1' // 'string'
typeof undefined // 'undefined'
typeof true // 'boolean'
typeof Symbol() // 'symbol'

typeof null // 'object'
typeof [] // 'object'
typeof {} // 'object'
typeof console // 'object'
typeof console.log // 'function'

typeof null 會(huì)輸出 object柴墩,這是 JS 存在的一個(gè)悠久 Bug,引用數(shù)據(jù)類(lèi)型 Object凫岖,用 typeof 來(lái)判斷的話江咳,除了 function 會(huì)判斷為 OK 以外,其余都是 'object'哥放,是無(wú)法判斷出來(lái)的

2.2 instanceof

new 一個(gè)對(duì)象歼指,那么這個(gè)新對(duì)象就是它原型鏈繼承上面的對(duì)象了,通過(guò) instanceof 我們能判斷這個(gè)對(duì)象是否是之前那個(gè)構(gòu)造函數(shù)生成的對(duì)象甥雕,這樣就基本可以判斷出這個(gè)新對(duì)象的數(shù)據(jù)類(lèi)型

let Car = function() {}
let benz = new Car()
benz instanceof Car // true

let car = new String('Mercedes Benz')
car instanceof String // true

let str = 'Covid-19'
str instanceof String // false
2.2.1 具體實(shí)現(xiàn)
function myInstanceof(left, right) {
  // 判斷是否為引用數(shù)據(jù)類(lèi)型
  if(typeof left !== 'object' || left === null) return false;

  // getProtypeOf是Object對(duì)象自帶的API踩身,能夠拿到參數(shù)的原型對(duì)象
  let proto = Object.getPrototypeOf(left);
  while(true) { // 循環(huán)往下尋找,直到找到相同的原型對(duì)象
    if(proto === null) return false;
    if(proto === right.prototype) return true; // 找到相同原型對(duì)象社露,返回true
    proto = Object.getPrototypeof(proto);
  }
}

console.log(myInstanceof(new Number(123), Number));    // true
console.log(myInstanceof(123, Number));                // false
  1. instanceof 可以準(zhǔn)確地判斷復(fù)雜引用數(shù)據(jù)類(lèi)型挟阻,但是不能正確判斷基礎(chǔ)數(shù)據(jù)類(lèi)型
  2. typeof也存在弊端,它雖然可以判斷基礎(chǔ)數(shù)據(jù)類(lèi)型(null 除外),但是引用數(shù)據(jù)類(lèi)型中附鸽,除了 function 類(lèi)型以外脱拼,其他的也無(wú)法判斷

2.3 Object.prototype.toString

toString() 是 Object 的原型方法,調(diào)用該方法拒炎,可以統(tǒng)一返回格式為 "[object Xxx]" 的字符串挪拟,其中 Xxx 就是對(duì)象的類(lèi)型。

Object.prototype.toString({})       // "[object Object]"
Object.prototype.toString.call({})  // 同上結(jié)果击你,加上call也ok
Object.prototype.toString.call(1)    // "[object Number]"
Object.prototype.toString.call('1')  // "[object String]"
Object.prototype.toString.call(true)  // "[object Boolean]"
Object.prototype.toString.call(function(){})  // "[object Function]"
Object.prototype.toString.call(null)   //"[object Null]"
Object.prototype.toString.call(undefined) //"[object Undefined]"
Object.prototype.toString.call(/123/g)    //"[object RegExp]"
Object.prototype.toString.call(new Date()) //"[object Date]"
Object.prototype.toString.call([])       //"[object Array]"
Object.prototype.toString.call(document)  //"[object HTMLDocument]"
Object.prototype.toString.call(window)   //"[object Window]"
2.3.1 具體實(shí)現(xiàn)
function getType(obj){
  let type  = typeof obj;
  // 先進(jìn)行typeof判斷玉组,如果是基礎(chǔ)數(shù)據(jù)類(lèi)型,直接返回
  if (type !== "object") { 
    return type;
  }

  // 對(duì)于typeof返回結(jié)果是object的丁侄,再進(jìn)行如下的判斷惯雳,正則返回結(jié)果
  return Object.prototype.toString.call(obj).replace(/^\[object (\S+)\]$/, '$1');
}

/* 代碼驗(yàn)證,需要注意大小寫(xiě)鸿摇,哪些是typeof判斷石景,哪些是toString判斷? */
getType([])     // "Array" typeof []是object拙吉,因此toString返回
getType('123')  // "string" typeof 直接返回
getType(window) // "Window" toString返回
getType(null)   // "Null"首字母大寫(xiě)潮孽,typeof null是object,需toString來(lái)判斷
getType(undefined)   // "undefined" typeof 直接返回
getType()            // "undefined" typeof 直接返回
getType(function(){}) // "function" typeof能判斷筷黔,因此首字母小寫(xiě)
getType(/123/g)      //"RegExp" toString返回

3. 數(shù)據(jù)類(lèi)型轉(zhuǎn)換

'123' == 123   // true
'' == null    // false
'' == 0        // true
[] == 0        // true
[] == ''       // true
[] == ![]      // true
null == undefined // true
Number(null)     // 0
Number('')      // 0
parseInt('')    // NaN
{} + 10  // 10
10 + {} // "10[object Object]"
// 對(duì)象在作為操作數(shù)時(shí)往史,解釋器總是優(yōu)先調(diào)用valueOf(), 而其他情況佛舱,解釋器總是認(rèn)為我們想要的是字符串椎例,所以會(huì)優(yōu)先調(diào)用toString()。 因此對(duì)象在前面返回結(jié)果就是Number;其他情況對(duì)象默認(rèn)用toString

let obj = {
  [Symbol.toPrimitive]() {
    return 200;
  },
  valueOf() {
    return 300;
  },
  toString() {
    return 'Hello';
  }
}
console.log(obj + 200); // 400

3.1 強(qiáng)制類(lèi)型轉(zhuǎn)換

強(qiáng)制類(lèi)型轉(zhuǎn)換方式包括 Number()请祖、parseInt()订歪、parseFloat()、toString()肆捕、String()刷晋、Boolean()

3.1.1 Number() 方法的強(qiáng)制轉(zhuǎn)換規(guī)則
轉(zhuǎn)換類(lèi)型 轉(zhuǎn)換結(jié)果
布爾值 true 和 false 分別被轉(zhuǎn)換為 1 和 0
數(shù)字 自身
null 0
undefined NaN
字符串 字符串中只包含數(shù)字(或者是 0X / 0x 開(kāi)頭的十六進(jìn)制數(shù)字字符串,允許包含正負(fù)號(hào))慎陵,則將其轉(zhuǎn)換為十進(jìn)制掏秩;<br />字符串中包含有效的浮點(diǎn)格式,將其轉(zhuǎn)換為浮點(diǎn)數(shù)值荆姆;<br />空字符串蒙幻,將其轉(zhuǎn)換為 0;<br />不是以上格式的字符串胆筒,均返回 NaN
Symbol 拋出錯(cuò)誤
對(duì)象 部署了 [Symbol.toPrimitive] 邮破,那么調(diào)用此方法诈豌,<br />否則調(diào)用對(duì)象的 valueOf() 方法,然后依據(jù)前面的規(guī)則轉(zhuǎn)換返回的值抒和;<br />如果轉(zhuǎn)換的結(jié)果是 NaN 矫渔,則調(diào)用對(duì)象的 toString() 方法,再次依照前面的順序轉(zhuǎn)換返回對(duì)應(yīng)的值
Number('0111');      //111
Number(null);        // 0
Number('');          // 0
Number('1a');        // NaN
Number(-0X11);       //-17
3.1.2 Boolean() 方法的強(qiáng)制轉(zhuǎn)換規(guī)則

除了 undefined摧莽、 null庙洼、 false、 ' '镊辕、 0(包括 +0油够,-0)、 NaN 轉(zhuǎn)換出來(lái)是 false征懈,其他都是 true

3.2 隱式類(lèi)型轉(zhuǎn)換

凡是通過(guò)邏輯運(yùn)算符 (&&石咬、 ||、 !)卖哎、運(yùn)算符 (+鬼悠、-、*亏娜、/)焕窝、關(guān)系操作符 (>、 <维贺、 <= 它掂、>=)、相等運(yùn)算符 (==) 或者 if/while 條件的操作幸缕,如果遇到兩個(gè)數(shù)據(jù)類(lèi)型不一樣的情況,都會(huì)出現(xiàn)隱式類(lèi)型轉(zhuǎn)換

3.2.1 '==' 的隱式類(lèi)型轉(zhuǎn)換規(guī)則
轉(zhuǎn)換類(lèi)型 轉(zhuǎn)換結(jié)果
類(lèi)型相同 無(wú)須進(jìn)行類(lèi)型轉(zhuǎn)換
其中一個(gè)操作值是 null 或者 undefined 另一個(gè)操作符必須為 null 或者 undefined晰韵,返回 true<br />否則返回 false
其中一個(gè)是 Symbol 類(lèi)型 返回 false
兩個(gè)操作值為 string 和 number 類(lèi)型 將字符串轉(zhuǎn)換為 number
一個(gè)操作值是 boolean 轉(zhuǎn)換成 number
一個(gè)操作值為 object 另一方為 string发乔、number 或者 symbol,就會(huì)把 object 轉(zhuǎn)為原始類(lèi)型再進(jìn)行判斷(調(diào)用 object 的 valueOf/toString 方法進(jìn)行轉(zhuǎn)換)
3.2.2 '+' 的隱式類(lèi)型轉(zhuǎn)換規(guī)則
轉(zhuǎn)換類(lèi)型 轉(zhuǎn)換結(jié)果
其中有一個(gè)是字符串 另外一個(gè)是 undefined雪猪、null 或布爾型栏尚,則調(diào)用 toString() 方法進(jìn)行字符串拼接,沒(méi)有toString()方法只恨,則調(diào)用 Strin译仗;<br />如果是純對(duì)象、數(shù)組官觅、正則等纵菌,則默認(rèn)調(diào)用對(duì)象的轉(zhuǎn)換方法,然后再進(jìn)行拼接
其中有一個(gè)是數(shù)字 另外一個(gè)是 undefined休涤、null咱圆、布爾型或數(shù)字笛辟,則會(huì)將其轉(zhuǎn)換成數(shù)字進(jìn)行加法運(yùn)算,<br />對(duì)象的情況還是參考上一條規(guī)則
其中一個(gè)是字符串 另一個(gè)是數(shù)字序苏,則按照字符串規(guī)則進(jìn)行拼接
'1' + undefined   // "1undefined"
'1' + null        // "1null"
'1' + true        // "1true"
'1' + 1n          // '11' 比較特殊字符串和BigInt相加手幢,BigInt轉(zhuǎn)換為字符串

1 + undefined     // NaN  規(guī)則2,undefined轉(zhuǎn)換數(shù)字相加NaN
1 + null          // 1
1 + true          // 2
1 + 1n            // 錯(cuò)誤 不能把BigInt和Number類(lèi)型直接混合相加

3.3 Object 的轉(zhuǎn)換規(guī)則

轉(zhuǎn)換類(lèi)型 轉(zhuǎn)換結(jié)果
如果部署了 Symbol.toPrimitive 方法 優(yōu)先調(diào)用再返回
調(diào)用 valueOf() 如果轉(zhuǎn)換為基礎(chǔ)類(lèi)型忱详,則返回
調(diào)用 toString() 如果轉(zhuǎn)換為基礎(chǔ)類(lèi)型围来,則返回
如果都沒(méi)有返回基礎(chǔ)類(lèi)型 會(huì)報(bào)錯(cuò)
var obj = {
  value: 1,
  valueOf() {
    return 2;
  },
  toString() {
    return '3'
  },
  [Symbol.toPrimitive]() {
    return 4
  }
}

console.log(obj + 1); // 5
// 因?yàn)橛蠸ymbol.toPrimitive,就優(yōu)先執(zhí)行這個(gè)匈睁;如果Symbol.toPrimitive這段代碼刪掉监透,則執(zhí)行valueOf打印結(jié)果為3;如果valueOf也去掉软舌,則調(diào)用toString返回'31'

// 再看兩個(gè)特殊的case:
10 + {}
// "10[object Object]"才漆,注意:{}會(huì)默認(rèn)調(diào)用valueOf是{},不是基礎(chǔ)類(lèi)型繼續(xù)轉(zhuǎn)換佛点,調(diào)用toString醇滥,返回結(jié)果"[object Object]",于是和10進(jìn)行'+'運(yùn)算

[1,2,undefined,4,5] + 10
// "1,2,,4,510"超营,注意[1,2,undefined,4,5]會(huì)默認(rèn)先調(diào)用valueOf結(jié)果還是這個(gè)數(shù)組鸳玩,不是基礎(chǔ)數(shù)據(jù)類(lèi)型繼續(xù)轉(zhuǎn)換,也還是調(diào)用toString演闭,返回"1,2,,4,5"不跟,然后再和10進(jìn)行運(yùn)算
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市米碰,隨后出現(xiàn)的幾起案子窝革,更是在濱河造成了極大的恐慌,老刑警劉巖吕座,帶你破解...
    沈念sama閱讀 211,817評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件虐译,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡吴趴,警方通過(guò)查閱死者的電腦和手機(jī)漆诽,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,329評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)锣枝,“玉大人厢拭,你說(shuō)我怎么就攤上這事∑踩” “怎么了供鸠?”我有些...
    開(kāi)封第一講書(shū)人閱讀 157,354評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)陨闹。 經(jīng)常有香客問(wèn)我回季,道長(zhǎng)家制,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,498評(píng)論 1 284
  • 正文 為了忘掉前任泡一,我火速辦了婚禮颤殴,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘鼻忠。我一直安慰自己涵但,他們只是感情好朝墩,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,600評(píng)論 6 386
  • 文/花漫 我一把揭開(kāi)白布佛呻。 她就那樣靜靜地躺著恕刘,像睡著了一般睬澡。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上景用,一...
    開(kāi)封第一講書(shū)人閱讀 49,829評(píng)論 1 290
  • 那天桥言,我揣著相機(jī)與錄音铅辞,去河邊找鬼埋酬。 笑死哨啃,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的写妥。 我是一名探鬼主播拳球,決...
    沈念sama閱讀 38,979評(píng)論 3 408
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼珍特!你這毒婦竟也來(lái)了祝峻?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 37,722評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤扎筒,失蹤者是張志新(化名)和其女友劉穎莱找,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體嗜桌,經(jīng)...
    沈念sama閱讀 44,189評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡奥溺,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,519評(píng)論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了症脂。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片谚赎。...
    茶點(diǎn)故事閱讀 38,654評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡淫僻,死狀恐怖诱篷,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情雳灵,我是刑警寧澤棕所,帶...
    沈念sama閱讀 34,329評(píng)論 4 330
  • 正文 年R本政府宣布,位于F島的核電站悯辙,受9級(jí)特大地震影響琳省,放射性物質(zhì)發(fā)生泄漏迎吵。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,940評(píng)論 3 313
  • 文/蒙蒙 一针贬、第九天 我趴在偏房一處隱蔽的房頂上張望击费。 院中可真熱鬧,春花似錦桦他、人聲如沸蔫巩。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,762評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)圆仔。三九已至,卻和暖如春蔫劣,著一層夾襖步出監(jiān)牢的瞬間坪郭,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,993評(píng)論 1 266
  • 我被黑心中介騙來(lái)泰國(guó)打工脉幢, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留歪沃,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,382評(píng)論 2 360
  • 正文 我出身青樓鸵隧,卻偏偏與公主長(zhǎng)得像绸罗,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子豆瘫,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,543評(píng)論 2 349

推薦閱讀更多精彩內(nèi)容