1齐帚、JavaScript中的數(shù)據(jù)類型
在JavaScript中高氮,我們把數(shù)據(jù)可以分為基本類型和引用類型。
1)基本數(shù)據(jù)類型:Number坎穿、String展父、Boolean、Undefined玲昧、null栖茉、symbol(es6新增,表示獨(dú)一無二的值)孵延,BigInt(es10新增)吕漂。
2)引用數(shù)據(jù)類型:Object。Object包括函數(shù)對(duì)象-Function尘应、普通對(duì)象-Object惶凝、數(shù)組對(duì)象-Array、正則對(duì)象-RegExp犬钢、日期對(duì)象-Date苍鲜、Math數(shù)學(xué)函數(shù)對(duì)象等。
注意:a玷犹、在數(shù)值類型中混滔,存在一種特殊數(shù)值NaN,意思為“不是數(shù)值”(可以使其他任何類型歹颓,所以NaN!=NaN坯屿。),用于表示返回?cái)?shù)值的操作失敗了(不是拋出錯(cuò)誤)晴股。isNaN用來檢測(cè)這個(gè)值是否為有效數(shù)字愿伴,不是有效數(shù)字則返回true,是有效數(shù)字返回false电湘。
b隔节、Undefined類型只有一個(gè)值就是特殊值undefined。當(dāng)聲明了變量但沒有初始化時(shí)寂呛,就相當(dāng)于給變量賦予了undefined值怎诫。
c、字符串一旦創(chuàng)建贷痪,值就不能改變了幻妓。如 let lang = "java"; lang = lang+"script" 。lang是先銷毀再創(chuàng)建劫拢。
d肉津、Null類型同樣只有一個(gè)值强胰,即特殊值null,表示一個(gè)空對(duì)象指針妹沙。這也是給typeof傳一個(gè)?null?會(huì)返回?"object"?的原因偶洋。(let?car?=?null; console.log(typeof?car);? //?"object")只要變量要保存對(duì)象,如果暫時(shí)沒有哪個(gè)對(duì)象可保存距糖,就可以用null來填充玄窝。undefined值由null值派生而來。(console.log(null?==?undefined);?//?true)
e悍引、基本數(shù)據(jù)類型和引用數(shù)據(jù)類型存儲(chǔ)在內(nèi)存中的位置不同恩脂。基本數(shù)據(jù)類型存儲(chǔ)在棧中,存放的是對(duì)應(yīng)的值趣斤;引用數(shù)據(jù)類型存儲(chǔ)在堆中俩块,在棧中存放的是指向堆內(nèi)存的地址。
2唬渗、數(shù)據(jù)類型檢測(cè)
1)typeof 檢測(cè)數(shù)據(jù)類型的邏輯運(yùn)算符
typeof?操作符返回一個(gè)字符串典阵,表示未經(jīng)計(jì)算的操作數(shù)的類型。直接在計(jì)算機(jī)底層基于數(shù)據(jù)類型的值(二進(jìn)制)進(jìn)行檢測(cè)镊逝。
typeof 對(duì)于原始類型:除了 null 都可以顯示正確的類型。
typeof對(duì)于對(duì)象:除了函數(shù)都會(huì)顯示object嫉鲸。所以說typeof并不能準(zhǔn)確判斷變量到底是什么類型,所以想判斷一個(gè)對(duì)象的正確類型撑蒜,這時(shí)候可以考慮使用instanceof。
2)instanceof 檢測(cè)是否為某個(gè)類的實(shí)例
instanceof?運(yùn)算符用于檢測(cè)構(gòu)造函數(shù)(類型的)的?prototype?屬性是否出現(xiàn)在某個(gè)實(shí)例對(duì)象的原型鏈上玄渗。
instanceof的實(shí)現(xiàn)原理:順著原型鏈去找座菠,直到找到相同的原型對(duì)象,返回true藤树,否則為false浴滴。
3)constructor 檢測(cè)構(gòu)造函數(shù)
如果我創(chuàng)建一個(gè)對(duì)象,更改它的原型岁钓,constructor就會(huì)變得不可靠了
4)Object.prototype.toString.call 檢測(cè)數(shù)據(jù)類型
如果需要通用檢測(cè)數(shù)據(jù)類型升略,可以采用Object.prototype.toString,調(diào)用該方法屡限,統(tǒng)一返回格式“[object Xxx]”的字符串品嚣,其中Xxx就是對(duì)象的類型。
對(duì)于Object對(duì)象钧大,直接調(diào)用toString()就能返回[object Object]翰撑;而對(duì)于其他對(duì)象,只要把Object.prototype.toString執(zhí)行啊央,讓它里面的this變?yōu)橐獧z測(cè)的值眶诈,即需要通過call來調(diào)用涨醋,才能返回正確的類型信息。
總結(jié):
typeof會(huì)返回一個(gè)變量的基本類型逝撬;instanceof返回的是一個(gè)布爾值吨枉;constructor返回的是一個(gè)布爾值;
instanceof可以準(zhǔn)確地判斷復(fù)雜引用數(shù)據(jù)類型腮介,但是不能正確判斷基礎(chǔ)數(shù)據(jù)類型续搀;我們可以肆意的修改原型的指向,所以檢測(cè)不準(zhǔn)確坎炼。
而typeof?也存在弊端愧膀,它雖然可以判斷基礎(chǔ)數(shù)據(jù)類型(null?除外,因?yàn)閷?duì)象存儲(chǔ)在計(jì)算機(jī)中谣光,都是以000開始的二進(jìn)制存儲(chǔ)檩淋,null也是,所以檢測(cè)出來的結(jié)果是對(duì)象)萄金,但是引用數(shù)據(jù)類型中蟀悦,除了function?類型以外,其他的也無法判斷(“object”)氧敢。
實(shí)現(xiàn):
傳遞的值是null或者undefined日戈,就返回對(duì)應(yīng)的字符串∷锕裕基本數(shù)據(jù)類型都采用typeof檢測(cè)浙炼。其他使用Object.prototype.toString。
3唯袄、JavaScript中的類型轉(zhuǎn)換機(jī)制
我們?cè)诼暶鞯臅r(shí)候只有一種數(shù)據(jù)類型弯屈,只有到運(yùn)行期間才會(huì)確定當(dāng)前類型。雖然變量的數(shù)據(jù)類型是不確定的恋拷,但是各種運(yùn)算符對(duì)數(shù)據(jù)類型是有要求的资厉,如果運(yùn)算子的類型與預(yù)期不符合,就會(huì)觸發(fā)類型轉(zhuǎn)換機(jī)制蔬顾。常見的類型轉(zhuǎn)換有:強(qiáng)制轉(zhuǎn)換(顯示轉(zhuǎn)換)宴偿、自動(dòng)轉(zhuǎn)換(隱式轉(zhuǎn)換)
1)常見的顯示轉(zhuǎn)換方法有:Number()、parseInt()阎抒、String()酪我、Boolean()
Number() 函數(shù)是將任意類型的值轉(zhuǎn)化為數(shù)值。轉(zhuǎn)化規(guī)則如下:
parseInt() 函數(shù)逐個(gè)解析字符且叁,遇到不能轉(zhuǎn)換的字符就停下來都哭。
parseInt() 方法首先查看位置 0 處的字符,判斷它是否是個(gè)有效數(shù)字;如果不是欺矫,該方法將返回 NaN纱新,不再繼續(xù)執(zhí)行其他操作。但如果該字符是有效數(shù)字穆趴,該方法將查看位置 1 處的字符脸爱,進(jìn)行同樣的測(cè)試。這一過程將持續(xù)到發(fā)現(xiàn)非有效數(shù)字的字符為止未妹,此時(shí) parseInt() 將把該字符之前的字符串轉(zhuǎn)換成數(shù)字簿废。例如,如果要把字符串 "12345red" 轉(zhuǎn)換成整數(shù)络它,那么 parseInt() 將返回 12345族檬,因?yàn)楫?dāng)它檢查到字符 r 時(shí),就會(huì)停止檢測(cè)過程化戳。
字符串中包含的數(shù)字字面量會(huì)被正確轉(zhuǎn)換為數(shù)字单料,比如 "0xA" 會(huì)被正確轉(zhuǎn)換為數(shù)字 10。不過点楼,字符串 "22.5" 將被轉(zhuǎn)換成 22扫尖,因?yàn)閷?duì)于整數(shù)來說,小數(shù)點(diǎn)是無效字符掠廓。
parseInt() 方法還有基模式换怖,可以把二進(jìn)制、八進(jìn)制却盘、十六進(jìn)制或其他任何進(jìn)制的字符串轉(zhuǎn)換成整數(shù)狰域。基是由 parseInt() 方法的第二個(gè)參數(shù)指定的黄橘,所以要解析十六進(jìn)制的值,需如下調(diào)用 parseInt() 方法:var iNum1 = parseInt("AF", 16);//返回 175屈溉。
parseInt(string,radix)
在沒有指定radix或者radix為0的情況下塞关,parseInt會(huì)按十進(jìn)制進(jìn)行轉(zhuǎn)換。然而子巾,這在某些情況下有點(diǎn)特殊:
如果string的值以“0x”開頭帆赢,parseInt會(huì)按十六進(jìn)制進(jìn)行轉(zhuǎn)換;
如果string的值以“0”開頭线梗,parseInt會(huì)按八進(jìn)制進(jìn)行轉(zhuǎn)換椰于。
parseInt("0x10"); //字符串以0x開頭則將之后的數(shù)字按16進(jìn)制解讀,16進(jìn)制的10也就是十進(jìn)制的16仪搔, 因此輸出為16
parseInt("0xa"); //10瘾婿,要注意16進(jìn)制包括0~9,a~f (也就是10~15),超出該范圍的字符不被解讀偏陪。
parseInt("0xg"); //NAN
這三個(gè)例子分別等價(jià)于 parseInt("0x10",16) ?parseInt("0xa",16) ?parseInt("0xg",16)/
parseInt()的參數(shù)是一個(gè)字符串類型抢呆;parseInt 會(huì)先調(diào)用 toString 方法。對(duì)于小于 1e-6 的數(shù)值來說笛谦,ToString 時(shí)會(huì)自動(dòng)轉(zhuǎn)換為科學(xué)計(jì)數(shù)法抱虐。 數(shù)值0.0000000007先會(huì)被轉(zhuǎn)換成字符串“7e-10”(科學(xué)計(jì)數(shù)法); 即執(zhí)行了parseInt("7e-10")饥脑; 字符e不是十進(jìn)制類型之后一起被截掉恳邀。
但是還存在下面的情況:當(dāng)大于 1e-6 的數(shù)值不會(huì)轉(zhuǎn)換為科學(xué)計(jì)數(shù)法。
parseFloat() 方法
對(duì)于這個(gè)方法來說灶轰,第一個(gè)出現(xiàn)的小數(shù)點(diǎn)是有效字符谣沸。如果有兩個(gè)小數(shù)點(diǎn),第二個(gè)小數(shù)點(diǎn)將被看作無效的框往。parseFloat() 會(huì)把這個(gè)小數(shù)點(diǎn)之前的字符轉(zhuǎn)換成數(shù)字鳄抒。這意味著字符串 "11.22.33" 將被解析成 11.22。
使用 parseFloat() 方法的另一不同之處在于椰弊,字符串必須以十進(jìn)制形式表示浮點(diǎn)數(shù)许溅,而不是用八進(jìn)制或十六進(jìn)制。該方法會(huì)忽略前導(dǎo) 0秉版,所以八進(jìn)制數(shù) 0102 將被解析為 102贤重。對(duì)于十六進(jìn)制數(shù) 0xA,該方法將返回 NaN清焕,因?yàn)樵诟↑c(diǎn)數(shù)中并蝗,x 不是有效字符。(注釋:經(jīng)測(cè)試秸妥,具體的瀏覽器實(shí)現(xiàn)會(huì)返回 0滚停,而不是 NaN。)
String() 函數(shù)可以將任意類型的值轉(zhuǎn)化成字符串粥惧。轉(zhuǎn)化規(guī)則如下:
Boolean() 函數(shù)可以將任意類型的值轉(zhuǎn)為布爾值键畴。在條件判斷時(shí),除了undefined突雪,null起惕,false,NaN咏删,''惹想,0,-0督函,其他所有值都轉(zhuǎn)為true嘀粱,包括所有對(duì)象激挪。
2)常見的隱式轉(zhuǎn)化場(chǎng)景
a、比較運(yùn)算(==草穆、!=灌灾、>、<)悲柱、if锋喜、while需要布爾值地方
b、算術(shù)運(yùn)算(+豌鸡、-嘿般、*、/涯冠、%)
運(yùn)算中其中一方為字符串炉奴,那么就會(huì)把另一方也轉(zhuǎn)換為字符串;如果一方不是字符串或者數(shù)字蛇更,那么會(huì)將它轉(zhuǎn)換為數(shù)字或者字符串瞻赶。
那么對(duì)于除了加法的運(yùn)算符來說,只要其中一方是數(shù)字派任,那么另一方就會(huì)被轉(zhuǎn)為數(shù)字砸逊。
自動(dòng)轉(zhuǎn)換為布爾值:在需要布爾值的地方,就會(huì)將非布爾值的參數(shù)自動(dòng)轉(zhuǎn)為布爾值掌逛,系統(tǒng)內(nèi)部會(huì)調(diào)用Boolean函數(shù)师逸。除了undefined、null豆混、false篓像、+0、-0皿伺、NaN员辩、"" 會(huì)被轉(zhuǎn)化成false,其他都換被轉(zhuǎn)化成true鸵鸥。
自動(dòng)轉(zhuǎn)換成字符串:遇到預(yù)期為字符串的地方屈暗,就會(huì)將非字符串的值自動(dòng)轉(zhuǎn)為字符串。具體規(guī)則是先將復(fù)合類型的值轉(zhuǎn)為原始類型的值脂男,再將原始類型的值轉(zhuǎn)為字符串。常發(fā)生在+運(yùn)算中种呐,一旦存在字符串宰翅,則會(huì)進(jìn)行字符串拼接操作。
自動(dòng)轉(zhuǎn)換成數(shù)值:除了+有可能把運(yùn)算子轉(zhuǎn)為字符串爽室,其他運(yùn)算符都會(huì)把運(yùn)算子自動(dòng)轉(zhuǎn)成數(shù)值汁讼。null轉(zhuǎn)為數(shù)值時(shí),值為0?。undefined轉(zhuǎn)為數(shù)值時(shí)嘿架,值為NaN瓶珊。
4、== 和 ===區(qū)別
等于操作符用兩個(gè)等于號(hào)( == )表示耸彪,如果操作數(shù)相等伞芹,則會(huì)返回?true。
由于JavaScript中存在隱式轉(zhuǎn)換蝉娜,等于操作符在比較中先進(jìn)行類型轉(zhuǎn)換唱较,再確定操作數(shù)是否相等。規(guī)則如下:
如果兩個(gè)都為簡(jiǎn)單類型召川,字符串和布爾值都會(huì)轉(zhuǎn)換成數(shù)值南缓,再比較是否相等;簡(jiǎn)單類型與引用類型比較荧呐,對(duì)象轉(zhuǎn)化成其原始類型的值汉形,再比較是否相等;兩個(gè)都為引用類型倍阐,則比較它們是否指向同一個(gè)對(duì)象概疆;null 和 undefined 相等;存在 NaN 則返回 false收捣;
全等操作符用 3 個(gè)等于號(hào)( === )表示届案,只有兩個(gè)操作數(shù)在不轉(zhuǎn)換的前提下相等才返回?true。即類型相同罢艾,值也需相同楣颠。null 和 undefined 不相等。