摘要:結(jié)合實(shí)際中的情況來(lái)看,有意或無(wú)意中涉及到隱式類(lèi)型轉(zhuǎn)換的情況還是很多的。此外當(dāng)進(jìn)行某些操作時(shí),變量可以進(jìn)行類(lèi)型轉(zhuǎn)換,我們主動(dòng)進(jìn)行的就是顯式類(lèi)型轉(zhuǎn)換,另一種就是隱式類(lèi)型轉(zhuǎn)換了。
前言
相信剛開(kāi)始了解js的時(shí)候,都會(huì)遇到 2 =="2",但 1+2 == 1+"2"為false的情況。這時(shí)候應(yīng)該會(huì)是一臉懵逼的狀態(tài),不得不感慨js弱類(lèi)型的靈活讓人發(fā)指,隱式類(lèi)型轉(zhuǎn)換就是這么猝不及防。結(jié)合實(shí)際中的情況來(lái)看,有意或無(wú)意中涉及到隱式類(lèi)型轉(zhuǎn)換的情況還是很多的。既然要用到,就需要掌握其原理,知其然重要知其所以然更重要。
js的變量類(lèi)型JavaScript 是弱類(lèi)型語(yǔ)言,意味著JavaScript 變量沒(méi)有預(yù)先確定的類(lèi)型。
并且變量的類(lèi)型是其值的類(lèi)型。也就是說(shuō)變量當(dāng)前的類(lèi)型由其值所決定,夸張點(diǎn)說(shuō)上一秒種的string,下一秒可能就是個(gè)array了。此外當(dāng)進(jìn)行某些操作時(shí),變量可以進(jìn)行類(lèi)型轉(zhuǎn)換,我們主動(dòng)進(jìn)行的就是顯式類(lèi)型轉(zhuǎn)換,另一種就是隱式類(lèi)型轉(zhuǎn)換了。例如:
var a = "1"; typeof a;//string a =parseInt(a); //顯示轉(zhuǎn)換為number typeof a //number a == "1" //true
弱類(lèi)型的特性在給我們帶來(lái)便利的同時(shí),也會(huì)給我們帶來(lái)困擾。趨利避害,充分利用該特性的前提就是掌握類(lèi)型轉(zhuǎn)換的原理,下面一起看一下。
js數(shù)據(jù)類(lèi)型老生常談的兩大類(lèi)數(shù)據(jù)類(lèi)型:
原始類(lèi)型
Undefined、 Null、 String、 Number、 Boolean
引用類(lèi)型
object
此外還有一個(gè)es6新增的Symbol,先不討論它。對(duì)于這五類(lèi)原始類(lèi)型,突然提問(wèn)可能想不全,沒(méi)必要去死記硬背,可以想一下為否的常見(jiàn)變量及其對(duì)應(yīng)值即可。
0 | Number |
---|---|
"" | String |
false | Boolean |
null | Null |
undefined | Undefined |
對(duì)于不同的數(shù)據(jù)格式轉(zhuǎn)換規(guī)則是不同的,我們需要分別對(duì)待。
轉(zhuǎn)換規(guī)則既然是規(guī)范定義的規(guī)則,那就不要問(wèn)為什么了,先大致看一下,爭(zhēng)取記住。是在不行經(jīng)常翻翻看看大佬的博客es5規(guī)范。轉(zhuǎn)換有下面這么幾類(lèi),我們分別看一下具體規(guī)范。(這部分轉(zhuǎn)換規(guī)則,完全可以跳過(guò)去,看到下面的實(shí)例再回頭看應(yīng)該更容易接受一些)
轉(zhuǎn)換為原始值
轉(zhuǎn)換為數(shù)字
轉(zhuǎn)換為字符串
ToPrimitive(轉(zhuǎn)換為原始值)ToPrimitive 運(yùn)算符接受一個(gè)值,和一個(gè)可選的 期望類(lèi)型 作參數(shù)。ToPrimitive 運(yùn)算符把其值參數(shù)轉(zhuǎn)換為非對(duì)象類(lèi)型。如果對(duì)象有能力被轉(zhuǎn)換為不止一種原語(yǔ)類(lèi)型,可以使用可選的 期望類(lèi)型 來(lái)暗示那個(gè)類(lèi)型。根據(jù)下表完成轉(zhuǎn)換
這段定義看起來(lái)有點(diǎn)枯燥。轉(zhuǎn)換為原始值,其實(shí)就是針對(duì)引用數(shù)據(jù)的,其目的是轉(zhuǎn)換為非對(duì)象類(lèi)型。
如果已經(jīng)是原始類(lèi)型,當(dāng)然就不做處理了
對(duì)于object,返回對(duì)應(yīng)的原始類(lèi)型,該原始類(lèi)型是由期望類(lèi)型決定的,期望類(lèi)型其實(shí)就是我們傳遞的type。直接看下面比較清楚。
ToPrimitive方法大概長(zhǎng)這么個(gè)樣子具體如下。
/** * @obj 需要轉(zhuǎn)換的對(duì)象 * @type 期望轉(zhuǎn)換為的原始數(shù)據(jù)類(lèi)型,可選 */ ToPrimitive(obj,type)
type可以為number或者string,兩者的執(zhí)行順序有一些差別
string:
調(diào)用obj的toString方法,如果為原始值,則返回,否則下一步
調(diào)用obj的valueOf方法,后續(xù)同上
拋出TypeError 異常
number:
調(diào)用obj的valueOf方法,如果為原始值,則返回,否則下一步
調(diào)用obj的toString方法,后續(xù)同上
拋出TypeError 異常
其實(shí)就是調(diào)用方法先后,畢竟期望數(shù)據(jù)類(lèi)型不同,如果是string當(dāng)然優(yōu)先調(diào)用toString。反之亦然。
當(dāng)然type參數(shù)可以為空,這時(shí)候type的默認(rèn)值會(huì)按照下面的規(guī)則設(shè)置
該對(duì)象為Date,則type被設(shè)置為String
否則,type被設(shè)置為Number
對(duì)于Date數(shù)據(jù)類(lèi)型,我們更多期望獲得的是其轉(zhuǎn)為時(shí)間后的字符串,而非毫秒值,如果為number,則會(huì)取到對(duì)應(yīng)的毫秒值,顯然字符串使用更多。
其他類(lèi)型對(duì)象按照取值的類(lèi)型操作即可。
概括而言,ToPrimitive轉(zhuǎn)成何種原始類(lèi)型,取決于type,type參數(shù)可選,若指定,則按照指定類(lèi)型轉(zhuǎn)換,若不指定,默認(rèn)根據(jù)實(shí)用情況分兩種情況,Date為string,其余對(duì)象為number。那么什么時(shí)候會(huì)指定type類(lèi)型呢,那就要看下面兩種轉(zhuǎn)換方式了。
toNumber某些特定情況下需要用到ToNumber方法來(lái)轉(zhuǎn)成number
運(yùn)算符根據(jù)下表將其參數(shù)轉(zhuǎn)換為數(shù)值類(lèi)型的值
對(duì)于string類(lèi)型,情況比較多,只要掌握常見(jiàn)的就行了。和直接調(diào)用Number(str)的結(jié)果一致,這里就不多提了,主要是太多提不完。
需要注意的是,這里調(diào)用ToPrimitive的時(shí)候,type就指定為number了。下面的toString則為string。
ToString 運(yùn)算符根據(jù)下表將其參數(shù)轉(zhuǎn)換為字符串類(lèi)型的值:
其實(shí)了解也很簡(jiǎn)單,畢竟是個(gè)規(guī)范,借用大佬一張圖:
雖然是需要死記的東西,還是有些規(guī)律可循的。
對(duì)于原始值:
Undefined,null,boolean
直接加上引號(hào),例如"null"
number 則有比較長(zhǎng)的規(guī)范,畢竟范圍比較大
常見(jiàn)的就是 "1" NaN則為"NaN" 基本等同于上面一條
對(duì)于負(fù)數(shù),則返回-+字符串 例如 "-2" 其他的先不考慮了。
對(duì)象則是先轉(zhuǎn)為原始值,再按照上面的步驟進(jìn)行處理。
valueOf當(dāng)調(diào)用 valueOf 方法,采用如下步驟:
調(diào)用ToObject方法得到一個(gè)對(duì)象O
原始數(shù)據(jù)類(lèi)型轉(zhuǎn)換為對(duì)應(yīng)的內(nèi)置對(duì)象, 引用類(lèi)型則不變
調(diào)用該對(duì)象(O)內(nèi)置valueOf方法.
不同內(nèi)置對(duì)象的valueOf實(shí)現(xiàn):
String => 返回字符串值
Number => 返回?cái)?shù)字值
Date => 返回一個(gè)數(shù)字,即時(shí)間值,字符串中內(nèi)容是依賴(lài)于具體實(shí)現(xiàn)的
Boolean => 返回Boolean的this值
Object => 返回this
對(duì)照代碼更清晰一點(diǎn)
var str = new String("123") //123 console.log(str.valueOf()) var num = new Number(123) //123 console.log(num.valueOf()) var date = new Date() //1526990889729 console.log(date.valueOf()) var bool = new Boolean("123") //true console.log(bool.valueOf()) var obj = new Object({valueOf:()=>{ return 1 }}) //依賴(lài)于內(nèi)部實(shí)現(xiàn) console.log(obj.valueOf())運(yùn)算隱式轉(zhuǎn)換
前面提了那么多抽象概念,就是為了這里來(lái)理解具體轉(zhuǎn)換的。
對(duì)于+運(yùn)算來(lái)說(shuō),規(guī)則如下:
+號(hào)左右分別進(jìn)行取值,進(jìn)行ToPrimitive()操作
分別獲取左右轉(zhuǎn)換之后的值,如果存在String,則對(duì)其進(jìn)行ToString處理后進(jìn)行拼接操作。
其他的都進(jìn)行ToNumber處理
在轉(zhuǎn)換時(shí)ToPrimitive,除去Date為string外都按照ToPrimitive type為Number進(jìn)行處理
說(shuō)的自己都迷糊了快,一起結(jié)合代碼來(lái)看一下
1+"2"+false
左邊取原始值,依舊是Number
中間為String,則都進(jìn)行toString操作
左邊轉(zhuǎn)換按照toString的規(guī)則,返回"1"
得到結(jié)果temp值"12"
右邊布爾值和temp同樣進(jìn)行1步驟
temp為string,則布爾值也轉(zhuǎn)為string"false"
拼接兩者 得到最后結(jié)果 "12false"
我們看一個(gè)復(fù)雜的
var obj1 = { valueOf:function(){ return 1 } } var obj2 = { toString:function(){ return "a" } } //2 console.log(1+obj1) //1a console.log("1"+ obj2) //1a console.log(obj1+obj2)
不管多復(fù)雜,按照上面的順序來(lái)吧。
1+obj1
左邊就不說(shuō)了,number
右邊obj轉(zhuǎn)為基礎(chǔ)類(lèi)型,按照type為number進(jìn)行
先調(diào)用valueOf() 得到結(jié)果為1
兩遍都是number,則進(jìn)行相加得到2
1+obj2
左邊為number
右邊同樣按照按照type為number進(jìn)行轉(zhuǎn)化
調(diào)用obj2.valueOf()得到的不是原始值
調(diào)用toString() return "a"
依據(jù)第二條規(guī)則,存在string,則都轉(zhuǎn)換為string進(jìn)行拼接
得到結(jié)果1a
obj1+obj2
兩邊都是引用,進(jìn)行轉(zhuǎn)換 ToPrimitive 默認(rèn)type為number
obj1.valueOf()為1 直接返回
obj2.valueOf()得到的不是原始值
調(diào)用toString() return "a"
依據(jù)第二條規(guī)則,存在string,則都轉(zhuǎn)換為string進(jìn)行拼接
得到結(jié)果1a
到這里相信大家對(duì)+這種運(yùn)算的類(lèi)型轉(zhuǎn)換了解的差不多了。下面就看一下另一種隱式類(lèi)型轉(zhuǎn)換
== 抽象相等比較這種比較分為兩大類(lèi),
類(lèi)型相同
類(lèi)型不同
相同的就不說(shuō)了,隱式轉(zhuǎn)換發(fā)生在不同類(lèi)型之間。規(guī)律比較復(fù)雜,規(guī)范比較長(zhǎng),這里也不列舉了,大家可以查看抽象相等算法。簡(jiǎn)單總結(jié)一句,相等比較就不想+運(yùn)算那樣string優(yōu)先了,是以number優(yōu)先級(jí)為最高。概括而言就是,都盡量轉(zhuǎn)成number來(lái)進(jìn)行處理,這樣也可以理解,畢竟比較還是期望比較數(shù)值。那么規(guī)則大概如下:
對(duì)于x == y
如果x,y均為number,直接比較
沒(méi)什么可解釋的了 1 == 2 //false
如果存在對(duì)象,ToPrimitive() type為number進(jìn)行轉(zhuǎn)換,再進(jìn)行后面比較
var obj1 = { valueOf:function(){ return "1" } } 1 == obj2 //true //obj1轉(zhuǎn)為原始值,調(diào)用obj1.valueOf() //返回原始值"1" //"1"toNumber得到 1 然后比較 1 == 1 [] == ![] //true //[]作為對(duì)象ToPrimitive得到 "" //![]作為boolean轉(zhuǎn)換得到0 //"" == 0 //轉(zhuǎn)換為 0==0 //true
存在boolean,按照ToNumber將boolean轉(zhuǎn)換為1或者0,再進(jìn)行后面比較
//boolean 先轉(zhuǎn)成number,按照上面的規(guī)則得到1 //3 == 1 false //0 == 0 true 3 == true // false "0" == false //true
如果x為string,y為number,x轉(zhuǎn)成number進(jìn)行比較
//"0" toNumber()得到 0 //0 == 0 true "0" == 0 //true結(jié)束語(yǔ) 參考文章
ECMAScript5.1中文版 + ECMAScript3 + ECMAScript(合集)
你所忽略的js隱式轉(zhuǎn)換
這篇文章的本意是為自己解惑,寫(xiě)到后面真的感覺(jué)比較乏味,畢竟規(guī)范性的東西多一點(diǎn),不過(guò)深入了解一下總好過(guò)死記硬背。原文請(qǐng)移步我的博客。對(duì)于有些觀點(diǎn)說(shuō)這些屬于js糟粕,完全不應(yīng)該深入,怎么說(shuō)呢,結(jié)合自己情況判斷吧。本人水平有限,拋磚引玉共同學(xué)習(xí)。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://m.specialneedsforspecialkids.com/yun/95189.html
摘要:與此相對(duì),強(qiáng)類(lèi)型語(yǔ)言的類(lèi)型之間不一定有隱式轉(zhuǎn)換。三為什么是弱類(lèi)型弱類(lèi)型相對(duì)于強(qiáng)類(lèi)型來(lái)說(shuō)類(lèi)型檢查更不嚴(yán)格,比如說(shuō)允許變量類(lèi)型的隱式轉(zhuǎn)換,允許強(qiáng)制類(lèi)型轉(zhuǎn)換等等。在中,加性運(yùn)算符有大量的特殊行為。 從++[[]][+[]]+[+[]]==10?深入淺出弱類(lèi)型JS的隱式轉(zhuǎn)換 本文純屬原創(chuàng)? 如有雷同? 純屬抄襲? 不甚榮幸! 歡迎轉(zhuǎn)載! 原文收錄在【我的GitHub博客】,覺(jué)得本文寫(xiě)的不算爛的...
摘要:隱式類(lèi)型轉(zhuǎn)換通常在邏輯判斷或者有邏輯運(yùn)算符時(shí)被觸發(fā)。一元加號(hào)執(zhí)行字符串的類(lèi)型轉(zhuǎn)換。邏輯運(yùn)算符和將值轉(zhuǎn)為型,但是會(huì)返回原始值不是。計(jì)算從表達(dá)式開(kāi)始,該表達(dá)式通過(guò)方法轉(zhuǎn)換為空字符串,然后轉(zhuǎn)換為??偨Y(jié)查看原文關(guān)注每日一道面試題詳解 類(lèi)型轉(zhuǎn)換是將值從一種類(lèi)型轉(zhuǎn)換為另一種類(lèi)型的過(guò)程(比如字符串轉(zhuǎn)數(shù)字,對(duì)象轉(zhuǎn)布爾值等)。任何類(lèi)型不論是原始類(lèi)型還是對(duì)象類(lèi)型都可以進(jìn)行類(lèi)型轉(zhuǎn)換,JavaScript 的...
摘要:等同于等同于其他類(lèi)型和布爾類(lèi)型之間的比較如果是布爾類(lèi)型,則返回的結(jié)果。 showImg(https://segmentfault.com/img/bVburFq?w=796&h=398); 前言 JavaScript作為一門(mén)弱類(lèi)型語(yǔ)言,我們?cè)诿刻斓木帉?xiě)代碼過(guò)程中,無(wú)時(shí)無(wú)刻不在應(yīng)用著值類(lèi)型轉(zhuǎn)換,但是很多時(shí)候我們只是在單純的寫(xiě),并不曾停下腳步去探尋過(guò)值類(lèi)型轉(zhuǎn)換的內(nèi)部轉(zhuǎn)換規(guī)則,最近通過(guò)閱讀你...
摘要:等同于等同于其他類(lèi)型和布爾類(lèi)型之間的比較如果是布爾類(lèi)型,則返回的結(jié)果。 showImg(https://segmentfault.com/img/bVburFq?w=796&h=398); 前言 JavaScript作為一門(mén)弱類(lèi)型語(yǔ)言,我們?cè)诿刻斓木帉?xiě)代碼過(guò)程中,無(wú)時(shí)無(wú)刻不在應(yīng)用著值類(lèi)型轉(zhuǎn)換,但是很多時(shí)候我們只是在單純的寫(xiě),并不曾停下腳步去探尋過(guò)值類(lèi)型轉(zhuǎn)換的內(nèi)部轉(zhuǎn)換規(guī)則,最近通過(guò)閱讀你...
摘要:等同于等同于其他類(lèi)型和布爾類(lèi)型之間的比較如果是布爾類(lèi)型,則返回的結(jié)果。 showImg(https://segmentfault.com/img/bVburFq?w=796&h=398); 前言 JavaScript作為一門(mén)弱類(lèi)型語(yǔ)言,我們?cè)诿刻斓木帉?xiě)代碼過(guò)程中,無(wú)時(shí)無(wú)刻不在應(yīng)用著值類(lèi)型轉(zhuǎn)換,但是很多時(shí)候我們只是在單純的寫(xiě),并不曾停下腳步去探尋過(guò)值類(lèi)型轉(zhuǎn)換的內(nèi)部轉(zhuǎn)換規(guī)則,最近通過(guò)閱讀你...
閱讀 1707·2021-11-12 10:36
閱讀 1623·2021-11-12 10:36
閱讀 3448·2021-11-02 14:46
閱讀 3813·2019-08-30 15:56
閱讀 3566·2019-08-30 15:55
閱讀 1468·2019-08-30 15:44
閱讀 1051·2019-08-30 14:00
閱讀 2744·2019-08-29 18:41