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