--- 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
Sign in via Google
Sign in via Facebook
Sign in via X(Twitter)
Sign in via GitHub
Sign in via Dropbox
Sign in with Wallet
Wallet (
)
Connect another wallet
Continue with a different method
New to HackMD?
Sign up
By signing in, you agree to our
terms of service
.