1. 程式人生 > >javascript中神奇的隱式轉換

javascript中神奇的隱式轉換

最常見的==和!=造成的隱式轉換,網上已經有很多人總結了,總結起來就一張圖:

ObjectStringNumberBoolean

不同型別之間做==或!=運算,會按箭頭方向轉換直到型別相等。
(undefined, null和NaN後面再細說)


下面是重點,到底哪些運算會造成隱式轉換呢?
按照我的理解,除了===和!==比較運算,其他所有的運算都會造成隱式轉換。
JS的運算子可以歸納為7大類:
1. 算術運算子
2. 賦值運算子
3. 比較運算子
4. 邏輯運算子
5. 三元運算子
6. 位運算子
7. 字串連線運算子
我們來逐個驗證。

1.算術運算子

+, -, *, /, %, ++, –

轉換規則1:所有型別均轉換為Number;
轉換規則2:null會轉換為0,undefined會轉換為NaN

   console.log(null + 1);     //1    +運算子作為字串連線符的例子請看第7條
   console.log(undefined - 1);     // NaN
   console.log([] * 1);    //0    []先轉換為String:'',再轉換為0
   console.log([1] / 1);    //1    [1]先轉換為String:'1',再轉換為1
console.log({} % 1); //NaN {}先轉換為String:'[object Object]',再轉換為NaN: var a = true; console.log(++a); //2 不能寫成++true, ++運算只能作用於變數 var a = false; console.log(--a); //-1

2.賦值運算子

=,+=,-=,*=,/=,%=

賦值運算的隱式轉換與算術運算同理,這裡就不再驗證了。

3.比較運算子

==, !=, >, >=, <, <=(不討論絕對等於)

轉換規則1:若均為基本型別,不需轉換;若均為複雜型別,做>和<比較需轉換為String再比較;
轉換規則2:若型別不同,按照最上圖進行轉換,直到型別相等,最終轉換為String或Number;
比較規則1:Number直接比較;String逐字元比較他們的unicode值;複雜型別比較引用的物件是否相同。
比較規則2:NaN既不等於任何值,也不大於和小於任何值;
比較規則3:undefined == null 返回true,兩者和除此之外所有型別都不相等。

console.log('true' == true);    //false    均轉換為Number,既 NaN == 1
console.log([] != true);    //true    均轉換為Number,既 0 != 1
console.log('a' > 1);    //false    均轉換為Number,既NaN>1
console.log('a' > '1');    //true    直接比較unicode值

4.三元運算子

a ? b : c

轉換規則1:第一個值會轉換為Boolean;
轉換規則2: 空字串/0/null/NaN/undefined會轉換為false,其他為true

console.log( [] ? 1 : 2);    //1

5.邏輯運算子

&&, ||, !

&& 和 || 轉換規則:所有型別均先轉換為Boolean做運算,再根據各自運算規則返回其中的一個原值;
! 轉換規則:所有型別均轉換為Boolean,並返回該Boolean的取反

console.log(undefined && 1);    //undefined
console.log({} || 'a');    //Object {}
console.log(!undefined);    //true

6.位運算子

~, &, |, ^, <<, >>, >>>

轉換規則1:所有型別均轉換為Number;
轉換規則2:NaN, null和undefined都會轉換為0(注意,與算術運算子不同)

console.log(~undefined);    //-1
console.log('25'&[3]);    //1
console.log({}|NaN);    //0
console.log({}^[1]);    //1
console.log(NaN<<1);    //0
console.log({}>>1);    //0
console.log(['6.6']>>>0);    //6

7.字串連線運算子

+

轉換規則:若運算子前後有一個為複雜型別或String型別,兩者均轉換為String型別

console.log(null+[]+1);    //null1

這麼多的隱式轉換,簡直是防不勝防。
那麼為什麼只有==這個運算的隱式轉換這麼受人關注呢?

一個原因是,其他運算子造成的隱式轉換就是我們想要的,比如算術運算子我們就是想得到Number,但是==運算不同,它的隱式轉換並不可控,出的意外更多;
另一個原因是,我們完全可以用===來避免這種隱式轉換,而其他的運算子就沒有這種待遇了。