相信剛開始瞭解js的時候,都會遇到 2 =='2',但 1+2 == 1+'2'爲false的狀況。這時候應該會是一臉懵逼的狀態,不得不感慨js弱類型的靈活讓人髮指,隱式類型轉換就是這麼猝不及防。結合實際中的狀況來看,有意或無心中涉及到隱式類型轉換的狀況仍是不少的。既然要用到,就須要掌握其原理,知其然重要知其因此然更重要。git
JavaScript 是弱類型語言,意味着JavaScript 變量沒有預先肯定的類型。
而且變量的類型是其值的類型。也就是說變量當前的類型由其值所決定,誇張點說上一秒種的string,下一秒可能就是個array了。此外當進行某些操做時,變量能夠進行類型轉換,咱們主動進行的就是顯式類型轉換,另外一種就是隱式類型轉換了。例如:es6
var a = '1'; typeof a;//string a =parseInt(a); //顯示轉換爲number typeof a //number a == '1' //true
弱類型的特性在給咱們帶來便利的同時,也會給咱們帶來困擾。趨利避害,充分利用該特性的前提就是掌握類型轉換的原理,下面一塊兒看一下。github
老生常談的兩大類數據類型:算法
此外還有一個es6新增的Symbol,先不討論它。對於這五類原始類型,忽然提問可能想不全,不必去死記硬背,能夠想一下爲否的常見變量及其對應值便可。學習
0 | Number |
---|---|
'' | String |
false | Boolean |
null | Null |
undefined | Undefined |
對於不一樣的數據格式轉換規則是不一樣的,咱們須要分別對待。this
既然是規範定義的規則,那就不要問爲何了,先大體看一下,爭取記住。是在不行常常翻翻看看大佬的博客es5規範。轉換有下面這麼幾類,咱們分別看一下具體規範。(這部分轉換規則,徹底能夠跳過去,看到下面的實例再回頭看應該更容易接受一些)es5
ToPrimitive 運算符接受一個值,和一個可選的 指望類型 做參數。ToPrimitive 運算符把其值參數轉換爲非對象類型。若是對象有能力被轉換爲不止一種原語類型,可使用可選的 指望類型 來暗示那個類型。根據下表完成轉換 spa
這段定義看起來有點枯燥。轉換爲原始值,其實就是針對引用數據的,其目的是轉換爲非對象類型。
若是已是原始類型,固然就不作處理了
對於object,返回對應的原始類型,該原始類型是由指望類型決定的,指望類型其實就是咱們傳遞的type。直接看下面比較清楚。
ToPrimitive方法大概長這麼個樣子具體以下。3d
/** * @obj 須要轉換的對象 * @type 指望轉換爲的原始數據類型,可選 */ ToPrimitive(obj,type)
type能夠爲number或者string,二者的執行順序有一些差異
string:code
number:
其實就是調用方法前後,畢竟指望數據類型不一樣,若是是string固然優先調用toString。反之亦然。
固然type參數能夠爲空,這時候type的默認值會按照下面的規則設置
對於Date數據類型,咱們更多指望得到的是其轉爲時間後的字符串,而非毫秒值,若是爲number,則會取到對應的毫秒值,顯然字符串使用更多。
其餘類型對象按照取值的類型操做便可。
歸納而言,ToPrimitive轉成何種原始類型,取決於type,type參數可選,若指定,則按照指定類型轉換,若不指定,默認根據實用狀況分兩種狀況,Date爲string,其他對象爲number。那麼何時會指定type類型呢,那就要看下面兩種轉換方式了。
某些特定狀況下須要用到ToNumber方法來轉成number
運算符根據下表將其參數轉換爲數值類型的值
對於string類型,狀況比較多,只要掌握常見的就好了。和直接調用Number(str)的結果一致,這裏就很少提了,主要是太多提不完。
須要注意的是,這裏調用ToPrimitive的時候,type就指定爲number了。下面的toString則爲string。
ToString 運算符根據下表將其參數轉換爲字符串類型的值:
其實瞭解也很簡單,畢竟是個規範,借用大佬一張圖:
雖然是須要死記的東西,仍是有些規律可循的。
對於原始值:
當調用 valueOf 方法,採用以下步驟:
不一樣內置對象的valueOf實現:
對照代碼更清晰一點
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())
前面提了那麼多抽象概念,就是爲了這裏來理解具體轉換的。
對於+運算來講,規則以下:
說的本身都迷糊了快,一塊兒結合代碼來看一下
1+'2'+false
咱們看一個複雜的
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
1+obj2
obj1+obj2
到這裏相信你們對+這種運算的類型轉換了解的差很少了。下面就看一下另外一種隱式類型轉換
這種比較分爲兩大類,
相同的就不說了,隱式轉換髮生在不一樣類型之間。規律比較複雜,規範比較長,這裏也不列舉了,你們能夠查看抽象相等算法。簡單總結一句,相等比較就不想+運算那樣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糟粕,徹底不該該深刻,怎麼說呢,結合本身狀況判斷吧。本人水平有限,拋磚引玉共同窗習。