寫在開篇之前:記錄學習點滴,如有錯誤與補充,希望大家積極指正。
js的數據類型
js數據類型:null
,undefined
,String
,Number
,Boolean
,Symbol
,Object
,其中
原始類型:Number
、String
、Null
、Undefined
、Boolean
引用類型:Object
,包含Array
JavaScript 是一種弱類型或者說動態語言。這意味着你不用提前聲明變量的類型,在程序運行過程中,類型會被自動確定。這也意味着你可以使用同一個變量保存不同類型的數據。
常見的隱式轉換場景
我們經常在開發過程中遇到如下場景:
-
if
判斷中
if(XXX){
...
}
複製代碼
這裏就發生了隱式轉換,我們知道if
的判斷條件是Boolean
類型,代碼在執行到if判斷時,js將XXX轉換成了Boolean類型。
- 比較操作符
"=="
[] == [] // false
{} == {} // false
[] != [] // true
複製代碼
看到這幾個比較操作,如果比較懵的話,沒關係,後面我會娓娓道來。
- 加號
"+"
與 減號"-"
var add = 1 + 2 + '3'
console.log(add); //'33'
var minus = 3 - true
console.log(minus); //2
複製代碼
可以看出有些情況下+
用作加號操作符
,有些時候+
作爲字符串連接符
,true
被轉換爲Number
類型,值爲1,相減後得到2。
-
.
點號操作符
var a = 2;
console.log(a.toString()); // '2';
var b = 'zhang';
console.log(b.valueOf()); //'zhang';
複製代碼
在對數字,字符串進行點操作調用方法時,默認將數字,字符串轉成對象。
- 關係運算符比較時
3 > 4 // false
"2" > 10 // false
"2" > "10" // true
複製代碼
如果比較運算符兩邊都是數字類型,則直接比較大小。如果是非數值進行比較時,則會將其轉換爲數字然後在比較,如果符號兩側的值都是字符串時,不會將其轉換爲數字進行比較,而是分別比較字符串中字符的Unicode編碼。
在討論之前我們需要先了解下
valueOf()
與toString
方法的一些要點。
-
toString()
和valueOf()
都是對象的方法 -
toString()
返回的是字符串,而valueOf()
返回的是原對象 -
undefined
和null
沒有toString()
和valueOf()
方法 - 包裝對象的
valueOf()
方法返回該包裝對象對應的原始值 - 使用
toString()
方法可以區分內置函數和自定義函數
大家沒事可以自己實踐下這兩個方法的使用和區別,其餘具體區別和特性不再詳述~
那麼接下來說說數據類型之間是如何轉換的吧。
String,Boolean,Number,對象之間的相互轉換
1. 其他類型轉爲字符串類型
- null:轉爲
"null"
。 - undefined:轉爲
"undefined"
。 - Boolean:
true
轉爲"true"
,false
轉爲"false"
。 - Number:
11
轉爲"11"
,科學計數法11e20
轉爲"1.1e+21"
。 - 數組:空數組
[]
轉爲空字符串""
,如果數組中的元素有null
或者undefined
,同樣當做空字符串處理,[1,2,3,4]
轉爲"1,2,3,4"
,相當於調用數組的join方法,將各元素用逗號","
拼接起來。 - 函數:
function a(){}
轉爲字符串是"function a(){}"
。 - 一般對象:相當於調用對象的toString()方法,返回的是
"[object,object]"
。
String(null) // "null"
String(undefined) // "undefined"
String(true) // "true"
String(false) // "false"
String(11) // "11"
String(11e20) // "1.1e+21"
String([]) // ""
String([1,null,2,undefined,3]) // 1,,2,,3
String(function a(){}) // "function a(){}"
String({}) // "[object,object]"
String({name:'zhang'}) // "[object,object]"
複製代碼
2. 其他類型轉爲Boolean類型
只有
null
,undefined
,0
,false
,NaN
,空字符串
這6種情況轉爲布爾值結果爲false
,其餘全部爲true
,例子如下
Boolean(null) // false
Boolean(undefined) // false
Boolean(0) // false
Boolean(false) // false
Boolean("false") // true
Boolean(NaN) // false
Boolean("") // false
Boolean([]) // true
Boolean({}) // true
複製代碼
3. 其他類型轉爲Number類型
- null:轉爲
0
。 - undefined:轉爲
NaN
。 - Boolean:
true
轉爲1
,false
轉爲0
。 - 字符串:如果是純數字的字符串,則轉爲對應的數字,如
11
轉爲"11"
,"1.1e+21"
轉爲1.1e+21
,空字符串
轉爲0
,其餘情況則爲NaN
。 - 數組:數組首先會被轉換成原始類型,即
primitive value
,得到原始類型後再根據上面的轉換規則轉換。 - 對象:和數組一樣
Number(null) // 0
Number(undefined) //NaN
Number(true) //1
Number(false) //0
Number("11") //11
Number("1.1e+21") //1.1e+21
Number("abc") //NaN
Number([]) // 0
Number([0]) // 0
Number([1]) // 1
Number(["abc"]) NaN
Number({}) // NaN
複製代碼
4. 對象轉爲其他類型(原始類型)
- 當對象轉爲其他原始類型時,會先調用對象的
valueOf()
方法,如果valueOf()
方法返回的是原始類型,則直接返回這個原始類型 - 如果
valueOf()
方法返回的是不是原始類型或者valueOf()方法
不存在,則繼續調用對象的toString()
方法,如果toString()
方法返回的是原始類型,則直接返回這個原始類型,如果不是原始類型,則直接報錯拋出異常。
注意:對於不同類型的對象來說,轉爲原始類型的規則有所不同,比如
Date
對象會先調用toString
var o1 = {
valueOf(){
return 1
}
}
var o2 = {
toString(){
return 2
}
}
var o3 = {
valueOf(){
return {}
},
toString(){
return 3
}
}
Number(o1) //1
Number(o2) //2
Number(o3) //3
複製代碼
o1
的valueOf
方法返回原始類型1
,故結果爲1
o2
沒有valueOf
方法,調用toString
方法得到原始類型2
,故結果爲2
o3
既有valueOf
方法,也有toString
方法,先調用valueOf
方法返回的不是原始類型,故繼續調用toString
方法,返回的是原始類型3
,故結果爲3
我們再看一個例子
將一個空數組
轉成Number
類型,空數組
是一個對象,先調用valueOf()
得到[]
,不是原始類型,繼續調用toString()
方法,得到的是一個空字符串
,根據Number
的轉換規則,空字符串
轉換成數字
爲0
,故Number([])
爲0
寬鬆相等(==)的隱式轉換
我們知道寬鬆相等是存在隱式轉換的,相比較時只要兩邊的值相等,不需要類型相等,就可以得到true
,那麼看看有哪些情況的比較吧
原始類型之間相比較
1. 字符串類型與數字類型相比較
- 當字符串類型與數字類型相比較時,
字符串類型
會被轉換爲數字類型
- 當字符串是由純數字組成的字符串時,轉換成對應的數字,字符串爲空時轉換爲
0
,其餘的都轉換爲NaN
。 小例子可如下:
"1" == 1 //true
"" == 0 //true
"1.1e+21" == 1.1e+21 //true
"Infinity" == Infinity //true
NaN == NaN //false 因爲NaN與任何值都不相等,包括自己
複製代碼
2. 布爾類型與其他類型相比較
- 只要
布爾類型
參與比較,該布爾類型
就會率先被轉成數字類型
- 布爾類型
true
轉爲1
,false
轉爲``0
小例子可如下:
true == 1 // true
false == 0 // true
true == 2 // false
"" == false // true
"1" == true // true
複製代碼
根據規則,布爾型參與比較,會把布爾類型轉爲數字類型。
- 第一個demo,
true
被轉爲數字類型1
,比較變爲1 == 1
,結果爲true
。 - 第二個demo,
false
被轉爲數字類型0
,比較變爲0 == 0
,結果爲true
。 - 第三個demo,
true
被轉爲數字類型1
,,比較變爲1 == 2
,結果爲false
。 - 第四個demo,
false
被轉爲數字類型0
,比較變爲"" == 0
,根據字符串與數字相比較,會率先把字符串變成數字,空字符串轉爲數字類型爲0,比較變爲0 == 0
,故結果爲true
。 - 第五個demo與第四個相似,
true
被轉換成數字類型1,比較變爲"1" == 1
,根據字符串與數字相比較,會率先把字符串變成數字,字符串"1"
轉爲數字類型爲1,變成1 == 1
,故結果爲true
。
null
類型和 undefined
類型與其他類型相比較
首先得知道null
與undefined
的定義
null
: 代表“空值”,代表一個空對象指針,使用typeof
運算得到 "object"
,所以可以認爲它是一個特殊的對象值。
undefined
:聲明瞭一個變量但並未爲該變量賦值,此變量的值默認爲undefined。
這裏多囉嗦一部分內容,null
與undefined
分別應用的場景:
null
的場景:
- 作爲原型鏈的終點
- 作爲函數的參數,表示該函數的參數不是對象
undefined
的場景:
- 聲明瞭一個變量但並未爲該變量賦值,此變量的值默認爲
undefined
- 函數沒有明確寫
return
,默認返回undefined
- 調用函數時,沒有傳參數,默認參數值爲
undefined
- 對象的某個屬性沒有賦值,默認值爲
undefined
Javascript規定null
與undefined
寬鬆相等(==
),並且都與自身相等,但是與其他所有值都不寬鬆相等。
null == null //true
undefined == undefined //true
null == undefined //true
null == 0 //false
null == false //false
undefined == 0 //false
undefined == false //false
null == [] //false
null == {} //false
unfefined == [] //false
undefined == {} //false
複製代碼
對象與原始類型的相比較
對象
與原始類型
相比較時,會把對象
按照對象轉換規則
轉換成原始類型
,再比較。
小例子如下:
{} == 0 // false
{} == '[object object]' // true
[] == false // true
[1,2,3] == '1,2,3' // true
複製代碼
先看一下,根據對象轉換規則,{}
,[]
,[1,2,3]
轉爲原始類型後的結果如下:
第一個例子,根據上圖可知,{}的原始值爲"[object object]"
,比較變成"[object object]" == 0
,接着根據字符串與數字類型相比較規則,先將字符串轉換成數字類型,可知[object object]
轉爲數字爲NaN
,比較變成NaN == 0
,因爲NaN
與任何值都不想等,故結果爲false
。
第二個例子,由第一個分析可知,{}的原始值爲"[object object]"
,比較變成"[object object]" =="[object object]"
,故結果爲true
。
第三個例子,根據上圖可知,[]
的原始值爲空字符串""
,比較變成"" == 0
,接着根據字符串與數字類型相比較規則,先將字符串轉換成數字類型,可知""
轉爲數字爲0
,比較變成0 == 0
,故結果爲true
。
第四個例子,根據數組轉換成原始類型的規則可知,數組的原始類型結果是由數組各個元素由逗號進行分割組成的字符串,故比較變成"1,2,3" == "1,2,3"
,所以結果爲true
。
對象與對象相比較
首先先說一下基本類型
(原始類型)與引用類型
的存儲。
基本類型
:是指存放在棧內存
中的簡單數據段,數據大小確定,內存空間大小可以分配,它們是直接按值存放的,所以可以直接按值訪問。
引用類型
:是指存放在堆內存
中的對象,變量名保存在棧內存
裏,而對應的值保存在堆內存
裏,這個變量在棧內存
中實際保存的是:這個值在堆內存中的地址
,也就是指針
,指針指向堆內存中的地址。
那麼對象相比較的規則就出來了:
如果兩個對象指向同一個對象,相等操作符返回
true
,否則爲false
。
var a = {};
var b = {};
a == b // false
var c = [];
var d = [];
c == d // false
複製代碼
雖然 a 和 b 都保存了一個 Object,但這是兩個獨立的 Object,它們的地址是不同的。c與d也是如此。 所以 [] == []
爲false
,{} == {}
也是false
。 那麼改成如下呢?
var a = {};
var b = a;
a == b;
複製代碼
變量b保存的是a的指針,指向同一個對象,所以a == b。
那麼接下來看下面的例子
[] == ![] // true
{} == !{} // false
複製代碼
Javascript規定,邏輯非 (!)
的優先級高於相等操作符 ( == )
再則取非
的含義時什麼呢?
取非
:首先通過Boolean()
函數將它的操作值轉換爲布爾值
,然後求反
。
第一個例子,先看![]
,也就是對空數組[]
取非,根據取非定義,先執行Boolean([])
,我們知道只有null
,undefined
,false
,0
,""
,NaN
,執行Boolean()
函數時結果才爲false
,取餘全爲true
,故Boolean([])
結果爲true
,取非得到false
,比較變爲[] == false
, 這下變成了對象類型
與布爾類型
相比較了,這就比較簡單了,根據前面的對象類型比較規則,布爾類型比較規則,很容易的出比較變爲"" == 0
,再根據字符串與數字類型相比較規則,比較變爲0 == 0
,顯然結果爲true
。
第二個例子,同第一個例子一樣,先執行Boolean({})
得到true
,再取反得到false
,比較變爲{} == false
,現在比較變爲對象類型
與布爾類型
相比較了,根據之前寫的例子知道,先指向{}的valueOf()方法得到的不是原始類型,繼續執行{}的toString()方法到的結果爲"[object object]"
,比較變爲"[object object]" == 0
,再根據字符串與數字類型相比較規則,"[object object]"
轉爲數字類型爲NaN
,比較變成NaN == 0
,NaN
不與任何值相等,顯然結果爲false
。
之前比較火的一個面試題:怎麼定義a
,可以使a==1&&a==2&&a==3
?結合對象隱式轉換規則,試一試吧!
字符串連接符(+)與加號運算符(+)如何區分
以下情況可視爲字符串連接符
- 含有
+
兩邊的數據,任意一個爲字符串 - 含有
+
兩邊的數據,其中一邊爲對象,並且取得的原始值爲字符串
以上2種情況都視爲字符串連接符,將自動的對不是字符串的數據執行String()方法轉爲字符串
以下情況可視爲加號運算符
- 加號兩邊都爲數字類型
- 加號兩邊都是基本類型,除了
字符串類型
,則可視爲加號
。也就是說加號兩邊可以爲Boolean
,Number
,null
,undefined
這種情況,肯定是加號運算符。將對不是Numebr
類型的數據執行Number()
方法再相加。 - 其中一邊是基本類型,字符串除外,另一邊是對象,並且對象獲得的原始值不是字符串。
另外值得一提的是: NaN
與任何數相加都爲NaN
,
那麼接下來看下面的例子
"a" + "b" // "ab"
"a" + 1 // "a1"
"a" + {} // "a[object object]"
"a" + [] // "a"
"a" + true // "atrue"
"a" + null // "anull"
"a" + undefined // "aundefined"
1 + 2 // 3
1 + true // 2
1 + null // 1
true + true // 2
true + false // 1
true + null // 1
false + null // 0
var c = {
valueOf(){
return 1;
}
}
1 + undefined // NaN
true + undefined // NaN
true + c // 2
1 + c // 2
NaN + 1 // NaN
NaN + null // NaN
[] + {} // "[object object]"
{} + [] // 0
複製代碼
這裏值得提出來的是Number(undefined)
爲NaN
,不難看出上面幾個的結果爲啥等於NaN
。 那麼[] + {}
與{} + []
只是調了一個位置,爲什麼結果會大不相同呢?
我們知道[]
的原始值爲""
,{}
的原始值爲[object object]
,在這裏就不再重述了。 那麼第一個例子,拼接起來等於"[object object]"
沒什麼問題,那麼第二個例子是爲什麼呢?
原來是js解釋器
會將開頭的 {}
看作一個代碼塊,而不是一個js對
象,於是運算可寫成+[]
,這結果可不就是0
嘛,上代碼看一下
[圖片上傳失敗...(image-bbb4d8-1623944329379)]
<figcaption></figcaption>
大家可以自己自己操作看看~~~
好了,大致就是這麼多了,也是看了很多文章和結合高程寫出來的,擼了一遍,着實加深了印象,給自己點個贊,嘻嘻嘻~~~
作者:Autumn秋田
鏈接:https://juejin.cn/post/6844903934876745735
來源:掘金
著作權歸作者所有。商業轉載請聯繫作者獲得授權,非商業轉載請註明出處。