我們在寫筆試題的時候,經常碰到涉及隱式轉換的題目,例如 "1" + 2 obj + 1 [] == ![] [null] == false 和 == = 叫做嚴格運算符,對象類型指向地址相同或原始類型( 數值、字元串、布爾值)值相同;叫做相等運算符,類型不同會進行轉化再比較,undefined、nu ...
"1" + 2 obj + 1 [] == ![] [null] == false
=== 和 ==
= 叫做嚴格運算符,對象類型指向地址相同或原始類型( 數值、字元串、布爾值)值相同;叫做相等運算符,類型不同會進行轉化再比較,undefined、null相等,對象類型還是比較引用。運算符將原始值和其包裝對象視為相等,但=運算符將它們視為不等。 所有obj.anull(相當於obj.a= null || obj.a ===undefined)。
相等運算符就是常常引起JS隱式轉換的坑貨,它也常常出現在我們的面試題中,不過我們在現實開發中,為了避免不必要的問題要求使用嚴格運算符,但是瞭解還是很有必要的。
想要瞭解JS隱式轉換,就要先從三個知識點下手。
原始類型
原始類型(基本類型、基本數據類型、原始數據類型)是一種既非對象也無方法的數據。在 JavaScript 中,共有7種:string,number,bigint,boolean,null,undefined,symbol (ECMAScript 2016新增)。
falsy 值 (虛值)
falsy 值 (虛值) 是在 Boolean 上下文中認定為 false 的值,在JavaScript只有 七個 falsy 值。
-
false false 關鍵字
-
0 數值 zero
-
0n 當 BigInt 作為布爾值使用時, 遵從其作為數值的規則. 0n 是 falsy 值.
-
一個空字元串 (字元串的長度為零). JavaScript 中的字元串可用雙引號 "", 單引號 '', 或 模板字面量 `` 定義。
-
null null - 缺少值
-
undefined undefined - 原始值
-
NaN NaN - 非數值
特別要說明的是,除了這七個對象全是真值,如new Number 和new Boolean 都是真值。
let b = new Boolean(false);i f(b){ //會執行到這裡。 }
四大轉換規則
-
toString規則:其他類型的值轉換為字元串類型的操作
-
null => "null"
-
undefined => "undefined"
-
true => "true" false=>"false"
-
10 => "10" "1e21"=>"1e+21"
-
[1,2,3] => "1,2,3"
-
Object對象 => "[Object Object]" 其實是調用toString方法
-
ToPrimitive規則:對象類型數組轉為原始類型的操作
-
當對象類型需要被轉為原始類型時,它會先查找對象的valueOf方法,如果valueOf方法返回原始類型的值,則ToPrimitive的結果就是這個值
-
如果valueOf不存在或者valueOf方法返回的不是原始類型的值,就會嘗試調用對象的toString方法,也就是會遵循對象的ToString規則,然後使用toString的返回值作為ToPrimitive的結果
-
Date 是先toString再ValueOf
-
如果在toString再ValueOf後都不能拿到原始類型,再判斷相等、加減時就拋出Uncaught TypeError: Cannot convert object to primitive value
-
ToNumber規則
-
null=> 0
-
undefined => NaN
-
"123"=>123 "12ssd"=>NaN ""=>0
-
false => 0 true=>1
-
數組、對象ToPrimitive
-
ToBoolean規則
-
js中七個falsy 值 (虛值) 為false,其他都為true
隱式轉換
有了對上面知識點的認識,我們可以來一舉拿下JS隱式轉換了。
-
== 的過程(優先換成數字、字元串)
-
首先看==前後有沒有NaN,有的話都是返回false。NaN不等於任何值,包括其本身
-
布爾值會轉成數字類型,true轉成1,false轉成0
-
數字和字元串比較,字元串會轉成數字
-
undefined和null除了和undefined或null相等,和其他相比都是false
-
數字或者字元串和對象相比,對象使用ToPrimitive規則轉換。
-
當兩個操作數都是對象時,JavaScript會比較其內部引用,當且僅當他們的引用指向記憶體中的相同對象(區域)時才相等,即他們在棧記憶體中的引用地址相同。
-
+的過程(優先換成字元串、數字)
-
如果至少有一個操作數是對象,它會被轉換成原始值(字元串,數字或布爾);
-
轉換之後,如果至少有一個操作數是字元串類型,第二個操作數會被轉換成字元串,並且會執行連接。
-
在其他的情況下,兩個操作數都會轉換成數字並執行算數加法運算。
-
-的過程(轉換成數字) 這個就很簡單了,全部用ToNumber規則轉換成數字
檢測學習成果
我們根據以上所學看幾個筆試題。如果你都知道結果,就不用看我的廢解釋了。
[] == [] [] == ![] [null] == false
第一個,左右都是對象,比較引用地址,這個兩個不同的實例,肯定不相等啊。 第二個,!的優先順序高於,所以先 [] 是真值,求非當讓是false了,轉成數字0,==左是對象右是數字,對象使用ToPrimitive規則轉換成"",再用ToNumber規則就轉成0了,判斷為相等。 第三個,[null]ToPrimitive再ToNumber規則就轉成0,false也轉成0。
var a = 1; var b = "3"; var obj1 = { i:1, toString:function() { return "1"; }, valueOf:function() { return 1; } }; var obj2 = { i:1, toString:function() { return "2"; } }; var obj3 = { i:1, valueOf:function() { return 3; } }; var obj = { i:1, }; var objE = { i:1, valueOf:function() { return []; }, toString:function() { return {}; } }; a+b a + obj a + objE a+obj1 a+obj2 a+obj3 b+obj1 b+obj2 b+obj3 a==obj2 a==obj1
這道題比較簡單你只要熟練掌握我上面說的那幾個知識點可以了。下麵直接寫出結果啦。
a + b //"13" a + obj //"1[object Object]" a + objE //Uncaught TypeError: Cannot convert object to primitive value a+obj1 //2 a+obj2 //"12" a+obj3 // 4 b+obj1 //"31" b+obj2 //"32" b+obj3 //“33” a==obj2 //false a==obj1 //true
最後提一個比較奇葩的題目。
定義一個變數a,使得下麵的表達式結果為true
a == 1 && a == 2 && a == 3
valueOf()在Object上預設返回的是對象不是原始類型,它會再調用toString。所以只要重寫toString也可以。
如果還是沒有思路,你們可以去看下這道題的文章原文從一道面試題說起—js隱式轉換踩坑合集。
更多學習內容觀看我的知乎:打造全網web高級前端工程師資料庫(總目錄)看完學的更加快,知識更牢固。你值得擁有(持續更新)~