天天看點

你不知道的JavaScript中的數值轉換規定實際運用

console.log(null == false);

開門見山,說出你的答案!

對,沒錯,答案是

false

讓我們一探究竟吧!

規定

先來閱讀以下兩份規則:

  • JavaScript 中的相等性判斷
  • 讀懂 ECMAScript 規格

嚴格相等 === :

全等操作符比較兩個值是否相等,兩個被比較的值在比較前都不進行隐式轉換。如果兩個被比較的值具有不同的類型,這兩個值是不全等的。否則,如果兩個被比較的值類型相同,值也相同,并且都不是 number 類型時,兩個值全等。最後,如果兩個值都是 number 類型,當兩個都不是 NaN,并且數值相同,或是兩個值分别為 +0 和 -0 時,兩個值被認為是全等的。
var num = ;
var obj = new String("0");
var str = "0";
var b = false;

console.log(num === num); // true
console.log(obj === obj); // true
console.log(str === str); // true

console.log(num === obj); // false
console.log(num === str); // false
console.log(obj === str); // false
console.log(null === undefined); // false
console.log(obj === null); // false
console.log(obj === undefined); // false
           

相等運算== :

The comparison x == y, where x and y are values, produces true or false.
  1. 如果x不是正常值(比如抛出一個錯誤),中斷執行。
  2. 如果y不是正常值,中斷執行。
  3. 如果Type(x)與Type(y)相同,執行嚴格相等運算x === y。
  4. 如果x是null,y是undefined,傳回true。
  5. 如果x是undefined,y是null,傳回true。
  6. 如果Type(x)是數值,Type(y)是字元串,傳回x == ToNumber(y)的結果。
  7. 如果Type(x)是字元串,Type(y)是數值,傳回ToNumber(x) == y的結果。
  8. 如果Type(x)是布爾值,傳回ToNumber(x) == y的結果。
  9. 如果Type(y)是布爾值,傳回x == ToNumber(y)的結果。
  10. 如果Type(x)是字元串或數值或Symbol值,Type(y)是對象,傳回x == ToPrimitive(y)的結果。
  11. 如果Type(x)是對象,Type(y)是字元串或數值或Symbol值,傳回ToPrimitive(x) == y的結果。
  12. return false。

那麼我們提煉以下規則:

  1. 如果 x或者y不是正常值,中斷執行。
  2. 如果 typeof x 和typeof y相同,執行x === y。
  3. 如果 x和y分别是null和undefined,傳回true。
  4. 如果 x和y分别是數值和字元串類型,那麼傳回 x == Number(y) (y 為字元串)
  5. 如果 x和y其中一個為布爾類型,那麼傳回x == Number(y) (若 x 為布爾類型)
  6. 如果 x和y分别是(Symbol值 或 數值 或 字元串) 和 對象,傳回x == ToPrimitive(y) (若 y 為對象)
  7. return false

1、将值轉為原始值,ToPrimitive()。

2、将值轉為數字,ToNumber()。

3、将值轉為字元串,ToString()。

1.ToPrimitive()

js引擎内部的抽象操作ToPrimitive有着這樣的簽名:

ToPrimitive(input, PreferredType?)

input是要轉換的值,PreferredType是可選參數,可以是Number或String類型。他隻是一個轉換标志,轉化後的結果并不一定是這個參數所值的類型,但是轉換結果一定是一個原始值(或者報錯)。

1.1如果PreferredType被标記為Number,則會進行下面的操作流程來轉換輸入的值。

1、如果輸入的值已經是一個原始值,則直接傳回它
2、否則,如果輸入的值是一個對象,則調用該對象的valueOf()方法,
   如果valueOf()方法的傳回值是一個原始值,則傳回這個原始值。
3、否則,調用這個對象的toString()方法,如果toString()方法傳回的是一個原始值,則傳回這個原始值。
4、否則,抛出TypeError異常。
           

1.2如果PreferredType被标記為String,則會進行下面的操作流程來轉換輸入的值。

1、如果輸入的值已經是一個原始值,則直接傳回它
2、否則,調用這個對象的toString()方法,如果toString()方法傳回的是一個原始值,則傳回這個原始值。
3、否則,如果輸入的值是一個對象,則調用該對象的valueOf()方法,
   如果valueOf()方法的傳回值是一個原始值,則傳回這個原始值。
4、否則,抛出TypeError異常。
           

既然PreferredType是可選參數,那麼如果沒有這個參數時,怎麼轉換呢?PreferredType的值會按照這樣的規則來自動設定:

、該對象為Date類型,則PreferredType被設定為String
、否則,PreferredType被設定為Number
           

toString()

valueOf()

的用法有待補充。

2.ToNumber()

根據參數類型進行下面轉換:

參數 結果
undefined NaN
null +0
布爾值 true轉換1,false轉換為+0
數字 無須轉換
字元串 有字元串解析為數字,例如:‘324’轉換為324,‘qwer’轉換為NaN
對象 先進行 ToPrimitive(obj, Number)轉換得到原始值,在進行ToNumber轉換為數字

3.ToString()

根據參數類型進行下面轉換:

參數 結果
undefined ‘undefined’
null ‘null’
布爾值 轉換為’true’ 或 ‘false’
數字 數字轉換字元串,比如:1.765轉為’1.765’
字元串 無須轉換
對象 先進行 ToPrimitive(obj, String)轉換得到原始值,在進行ToString轉換為字元串

Object.is():

Object.is()

判斷兩個值是否相同。如果下列任何一項成立,則兩個值相同:

  • 兩個值都是 undefined
  • 兩個值都是 null
  • 兩個值都是 true 或者都是 false
  • 兩個值是由相同個數的字元按照相同的順序組成的字元串
  • 兩個值指向同一個對象
  • 兩個值都是數字并且
  • 都是正零 +0
  • 都是負零 -0
  • 都是 NaN
  • 都是除零和 NaN 外的其它同一個數字

這種相等性判斷邏輯和傳統的

==

運算符所用的不同,

==

運算符會對它兩邊的操作數做隐式類型轉換(如果它們類型不同),然後才進行相等性比較,(是以才會有類似

"" == false

true

的現象),但

Object.is

不會做這種類型轉換。

這與

===

運算符也不一樣。

===

運算符(和

==

運算符)将數字值

-0

+0

視為相等,并認為

Number.NaN

不等于

NaN

示例:

Object.is('foo', 'foo');     // true
Object.is(window, window);   // true

Object.is('foo', 'bar');     // false
Object.is([], []);           // false

var test = { a:  };
Object.is(test, test);       // true

Object.is(null, null);       // true

// 特例
Object.is(, -);            // false
Object.is(-, -);           // true
Object.is(NaN, /);         // true
           

實際運用

我們先看以下以下幾種值比較的結果:

你不知道的JavaScript中的數值轉換規定實際運用

挑選重點來分析如下:

左邊數組類型為

Obeject

,右邊是

String

,滿足總結條件6。

執行

ToPrimitive([1,2])

,在沒有參數的情況下且不為

Date

類型,轉換類型自動為

Number

再執行

[1,2].valueOf()

,類型還是

Obeject

,不為原始值

再執行

[1,2].toString()

"1,2"

為字元串原始值

最後比較

"1,2" == "1,2"

,傳回

true

開始的那個問題:

因為

false

是Boolean類型,滿足總結中的第五條,是以實際比較

Number(bull) == false;
 == null;
//false
           

最新的 ECMAScript 标準定義了 7 種資料類型:

6 種 原始類型:

Boolean

Null

Undefined

Number

String

Symbol (ECMAScript 6 新定義)

和 Object

0 == null

null的類型是

Null

,實際上這個比較不滿足轉換的任何一條規則,是以傳回

false

兩邊都是

Number

類型,是以比較全等

===

傳回false

從數值的角度上講

NaN

不與任何值相等。

繼續閱讀