--- title: 'JS 核心 7 - 寬鬆相等、嚴格相等以及隱含轉型' tags: JS 核心, Javascript, 寬鬆相等、嚴格相等以及隱含轉型 description: 2021/02/03 --- JS 核心 -- 寬鬆相等、嚴格相等以及隱含轉型 === ## 嚴格相等 : === (嚴格相等)、!== (嚴格不相等) **型別**和**數值**都要相等。 (不會替數值做自動轉型) ``` console.log( 1 === '1' ); // false console.log( 1 === 1 ); // true console.log( 1 !== '1' ); // true (嚴格相等否定) ``` 以下是幾個值得特別注意的例子: NaN 不等於自己 ( NaN 不大於、不小於也不等於任何數字,所以也不等於它自己 ) ``` console.log( NaN === NaN ); // false,兩個 (不是數值) 做比對 console.log( +0 === -0 ); // true,雖然值不同,但會回傳true ``` ## 寬鬆相等 : == (寬鬆相等)、!= (寬鬆不相等) 值和型別**不**完全相同,可能會回傳true ## ☞ 簡略規則 <span class="green">型別相同,就會以同一型做比較,但要注意</span> 1. NaN 不等於自己 ( NaN 不大於、不小於也不等於任何數字,所以也不等於它自己 ) 2. +0、-0 彼此相等 3. 物件 (含 Function 和 Array ) 的相等是比較參考(reference),若參考相等才是相等 <span class="green">型別不同,將其中一個或兩個值先做強制轉型,再用型別相同的做比較</span> 1. 字串轉為**數字** 2. 布林轉為**數字** 3. **null 與 undefined** 在寬鬆相等下<span class="red">會強制轉型為彼此,不會轉為數字型別,</span>因此是相等的但不等於其他值 ``` console.log( Number(null) , Number(undefined) ); // 0 NaN console.log( null == 0 ); // false(null不會轉成數字做比對) console.log( null == undefined ); // true console.log( null === undefined ); // false ``` <span class="green">若比較的對象是物件,優先使用 valueOf(..),再使用 toString(..) ,將物件取得基本型別的值,再做比較。</span> 物件和非物件比對-<span class="red">**使用包裹物件轉換**</span> ``` console.log( [10] ); console.log( Number([10]) ); // 10 (加上包裹物件後,得到數字) console.log( 10 == [10] ); // true console.log( ['A'] ); console.log( String(['A']) ); // A (加上包裹物件後,得到字串) console.log( 'A' == ['A'] ); // true ``` 物件和物件比對-<span class="red">**注意參考位置**</span> (比對的不是物件裡的值,而是他的參考位置) ``` console.log({} == {}); // false (兩者參考位置不同) console.log([] == []); // false (兩者參考位置不同) var a = []; var b = a; // b 取得陣列 a 的參考位置 console.log( a == b ); // true (a 和 b 都使用同一個參考路徑) console.log( a === b ); // true ``` <span class="green">例外 : 0 代表 false , !0 代表 true。</span> ``` console.log( 0 ); // 0 (又代表false) console.log( !0 ); // true console.log( Number(!0) ); // 1 console.log( '1' == !0 ); // true (布林和字串比對,會自動轉型為數字) ``` ✏ **範例 :** 數字和字串比對-字串自動轉為<span class="red">**數值**</span> ``` console.log( 1 == '1' ); // true ( '1'自動轉為數值做比對 ) console.log( Number('1') ); // 1 (轉換字串為數值) console.log( 17 == '0x11' ); // true (0x 代表將數值轉為 16 進位,11 代表 16+1) console.log( Number('0x11') ); // 17 (轉換字串為數值) ``` ✏ **範例 :** 布林和字串比對-兩者都會自動轉為<span class="red">**數值**</span> (可參考下段 "轉型" 的筆記) ``` console.log( true == 'true' ); // false console.log( Number('true') ); // NaN (字串無法轉為正常的數值) console.log( Number(true) ); // 1 console.log( true == '1' ); // true console.log( false == '0' ); // true console.log( true == 1 ); // true console.log( false == 0 ); // true console.log( 1 != '1' ); // false (右邊字串 '1' 被轉型為數字 1) ``` ✏ **範例 :** 純物件 - 使用 <span class="red">**String**</span> 做轉換 ``` // 通常不會這樣做比對,僅供參考 console.log( { A : 'A' } ); // { A : 'A' } console.log( String({ A : 'A' }) ); // [object Object] console.log( '[object Object]' == { A : 'A' } ); // true ``` ## 轉型 ### ToString : 任何非字串的值被強制轉型為字串,規則說明如下 * undefined ->'undefined' * null -> 'null' * boolean 的 true -> 'true'、false -> 'false' * number -> '1.234' * object 若有定義其 toString 方法,則會以它自己的 toString 方法所產生的結果為優先 ``` // 陣列有自己定義的 toString 方法 [1,2,3].toString(); // "1,2,3" ``` 若沒有定義 toString 方法,則回傳內部的屬性 [[Class]] , 這是一個用來標記這個值是屬於物件的哪個子分類的標籤 ``` ({}).toString() // [object Object] ``` ### ToNumber : 將非數字值當成數字來操作,規則說明如下 * undefined -> NaN * null -> +0 即是 0 * boolean 的 true -> 1、false -> +0 即是 0 * number -> 不轉換 * string -> 數字或 NaN,結果與 Number ( input ) 是一樣的 * object -> 若有定義其 valueOf 方法,會優先使用 valueOf 取得其原始型別值,反之,若沒有定義 valueOf 方法,則改用 toString 方法取得其原始型別值,再用 Number(..) 轉為數字。 ### ToBoolean Truthy 與 Falsy 的概念,在 JavaScript 中會是 **false 值**如下 * "" ‒ 空字串 * 0、 -0、 NaN * null * undefined * false 除了以上之外,其餘都會被轉為 true,但其中比較特殊的如下 * [ ] * { } * function foo ( ) { } ‒ 函式 * '0' ‒ 文字的 0 * ' ' ‒ 包含空白的引號 ### 強制轉型 ``` // 使用內建函式: String(123) // "123" Number('123') // 123 ----------------------------- // 使用物件原型方法: (123).toString() // "123" ----------------------------- // 使用一元正/負運算子: +('123’) / -('-123') // 123 / 123 ``` ### 隱含轉型 : 程式碼中某個型別轉換動作是沒有明確指出要轉換型,但卻有轉型的動作 ☞ **物件與非物件** : 會透過包裹物件來進行型別轉換,最後再執行比對動作。 陣列 [10] 為物件,當數字與物件進行寬鬆比對時,先操作將物件轉換成數字,最後再進行比對 ``` console.log( 10 == [10] ); // true ``` 陣列 [‘A’] 為物件,當字串與物件進行寬鬆比對時,先操作將物件轉換成字串,最後再進行比對 ``` console.log( 'A' == ['A'] ); // true ``` ## :memo: 學習回顧 :::info * 嚴格相等、寬鬆相等的差異是在做**值的比較**時是否會做**強制轉型** * 型別相同,就會以同一型做比較 * NaN 不等於自己 ( NaN 不大於、不小於也不等於任何數字,所以也不等於它自己 ),console.log( NaN === NaN ); // false * +0、-0 彼此相等,console.log( +0 === -0 ); // true, * 型別不同,將其中一個或兩個值先做強制轉型,再用型別相同的做比較 * 字串轉為**數字** * 布林轉為**數字** * 布林和字串比對,兩者都轉為**數字** * **null 與 undefined** 在寬鬆相等下<span class="red">會強制轉型為彼此,不會轉為數字型別,</span>因此是相等的但不等於其他值 * console.log( Number(null) , Number(undefined) ); // 0 NaN * console.log( null == 0 ); // false(null不會轉成數字做比對) * console.log( null == undefined ); // true * console.log( null === undefined ); // false * 物件和非物件比對-使用包裹物件轉換 * 物件和物件比對-比對的不是物件裡的值,而是他的參考位置 * 例外 : 0 代表 false , !0 代表 true * console.log( !0 ); // true * console.log( Number(!0) ); // 1 ::: ## :+1: 相關參考文件 :::info [桑莫 - 強制轉型](https://cythilya.github.io/2018/10/15/coercion/#%E6%98%8E%E7%A2%BA%E7%9A%84%E5%BC%B7%E5%88%B6%E8%BD%89%E5%9E%8Bexplicit-coercion) [強制轉型、註解、變數、範疇](https://www.coderbridge.com/series/9e5162da940f473a9f1cfeece124ee98/posts/f4a2d1e05f1c4a29a459f9cf0591d026) [kuro - 「比較」與自動轉型的規則](https://ithelp.ithome.com.tw/articles/10191254) [kuro - 運算式與運算子](https://ithelp.ithome.com.tw/articles/10191180) [包裹物件、自動轉型](https://jimmywei01.github.io/2019/05/28/JS-%E7%B4%80%E9%8C%842-%E5%8C%85%E8%A3%B9%E7%89%A9%E4%BB%B6%E3%80%81%E8%87%AA%E5%8B%95%E8%BD%89%E5%9E%8B/) [包裹物件、強制轉型](https://medium.com/j51217123/js-%E5%AD%B8%E7%BF%92%E7%AD%86%E8%A8%98-%E5%8C%85%E8%A3%B9%E7%89%A9%E4%BB%B6-%E5%BC%B7%E5%88%B6%E8%BD%89%E5%9E%8B-13ff82fea540) ::: <style> .red { color: red; } .green { color: green; } </style>
×
Sign in
Email
Password
Forgot password
or
By clicking below, you agree to our
terms of service
.
Sign in via Facebook
Sign in via Twitter
Sign in via GitHub
Sign in via Dropbox
Sign in with Wallet
Wallet (
)
Connect another wallet
New to HackMD?
Sign up