本篇文章主要是講述在JavaScript中判斷兩個值相等,不要認為很簡單,要注意的是在JavaScript中存在4種不同的相等邏輯。
ECMAScript 是 JavaScript 的語言規范,在ECMAScript 規范中存在四種相等算法,如下圖所示:
上圖中每個依次寫下來,很多前端應該熟悉嚴格相等和非嚴格相等,但對于同值零和同值卻不熟悉,現在就依次下面四種方法。
同值
同值零
非嚴格相等
嚴格相等
非嚴格相等
非嚴格相等使用兩個等號,這個雙等就很熟悉,非嚴格相等表示語義相等,不要求類型一樣,非嚴格相等在比較前會先將比較參數類型轉換為一致,要再次進行比較,代碼示例如下:
1 == 1; // true 1 == '1'; // true 類型不同,不影響比較結果
非嚴格相等有非常復雜的轉換規則,非常難以記憶,社區中有人將上面的規則總結成了圖片,一圖勝千言,如下圖所示:
這么多,我們要先進行總結,就是如下三條規則:
Undefined 只和 Null 相等
和 Number 比較時,另一個值會自動轉換為 Number
和 Boolean 比較時,另一個值會轉換為 Number
如果值為對象,會使用內部的 ToPrimitive 轉換,可以通過自定義 Symbol.toPrimitive 改變返回值,需要注意的是在相等的判斷中 Symbol.toPrimitive 接受的 hint 參數都是 default。
const obj = { [Symbol.toPrimitive](hint) { console.log(hint); if (hint == 'number') { return 1; } if (hint == 'string') { return 'yan'; } return true; }, }; console.log(obj == 1); // obj 返回 true console.log(obj == '1'); // obj 返回 true console.log(obj == true); // obj 返回 true
其實非嚴格相等并不可以帶來很多便利,換個角度,可以通過隱式的自動轉換,簡化了部分場景的工作,比如 Number 和 String 的自動轉換,簡化了前端從表單,url 參數中獲取值的比較問題,但自動轉換帶來的問題比便利還多。
隱式轉換的規則,這個在很多情況下就不適用,對于現在的觀點并不建議是引用,作者建議只在判斷 undefined 和 null 的場景下可以使用非嚴格相等。
嚴格相等
嚴格相等是另一種比較算法,其和非嚴格想等的區別是不會進行類型轉換,類型不一致時直接返回 false,嚴格相等對應===操作符,因為使用三個等號,也被稱作三等或者全等,嚴格相等舉例:
1 === 1; // true 1 === '1'; // false 類型不同,影響比較結果
重點:在不同類型值判斷規則下圖所示,與前面的非嚴格相等對比,總的來說嚴格相等更符合直覺。
嚴格相等解決了非嚴格相等中隱式轉換帶來的問題,但也丟失了隱式轉換帶來的便利,主要是可能對于類型不一致的情況,比如從表單中獲取的值都是字符串,其實保守的做法就是在比較前手動類型轉換,代碼示例如下:
1 === Number('1'); // true 手動類型轉換,類型防御
嚴格相等幾乎總是正確的,可有例外,比如 NaN 和正負 0 的問題。
Number 類型有個特殊的值 NaN,用來表示計算錯誤的情概況,比較常見是非 Number 類型和 Number 類型計算時,會得到 NaN 值,代碼示例如下所示,這是從表單和接口請求獲取數據時很容易出現的問題。
const a = 0 / 0; // NaN const b = 'a' / 1; const c = undefined + 1; // NaN
在嚴格相等中,NaN 是不等于自己的,NaN 是(x !== x) 成立的唯一情況,這種狀況下是可以判斷 NaN 的,可以使用 isNaN 進行判斷,ECMAScript 2015 引入了新的 Number.isNaN,和 isNaN 的區別是不會對傳入的參數做類型轉換,建議使用語義更清晰的 Number.isNaN,但是要注意兼容性問題,判斷 NaN 代碼示例如下:
NaN === NaN; // false isNaN(NaN); // true Number.isNaN(NaN); // true isNaN('aaa'); // true 自動轉換類型 'aaa'轉換為Number為NaN Number.isNaN('aaa'); // false 不進行轉換,類型不為Number,直接返回false
嚴格相等另一個例外情況是,無法區分+0 和-0,代碼示例如下,在一些數學計算場景中是要區分語義的。
+0 === -0; // true
JavaScript 中很多系統函數都使用嚴格相等,比如數組的 indexOf,lastIndexOf 和 switch-case 等,需要注意,這些對于 NaN 無法返回正確結果,代碼示例如下:
[NaN].indexOf(NaN); // -1 數組中其實存在NaN [NaN].lastIndexOf(NaN); // -1
同值零
同值零是另一種相等算法,名字來源于規范的直譯,規范中叫做 SameValueZero,同值零和嚴格相等功能一樣,除了處理 NaN 的方式,同值零認為 NaN 和 NaN 相等,這在判斷 NaN 是否在集合中的語義下是非常合理的。
ECMAScript 2016 引入的 includes 使用此算法,此外 Map 的鍵去重和 Set 的值去重,使用此算法,代碼示例如下:
[NaN].incdudes(NaN); // true 注意和indexOf的區別,incdudes的語義更合理 new Set([NaN, NaN]); // [NaN] set中只會有個一個NaN,如果 NaN !== NaN的話,應該是[NaN, NaN] new Map([ [NaN, 1], [NaN, 2], ]); // {NaN => 2} 如果 NaN !== NaN的話,應該是 {NaN => 1, NaN => 2}
同值
同值是最后一種相等算法,其和同值零類似,但認為 +0 不等于 -0,ECMAScript 2015 帶來的 Object.is 使用同值算法,代碼示例如下:
Object.is(NaN, NaN); // true Object.is(+0, -0); // false ???? 注意這里
同值算法的使用場景是,確定兩個值是否在任何情況下功能上是相同的,比較不常用,defineProperty 使用此算法確認鍵是否存在,例如,將存在的只讀屬性值-0 修改為+0 時會報錯,如果設置為同樣的-0 將執行正常,代碼示例如下:
function test() { 'use strict'; // 需要開啟嚴格模式 var a = {}; Object.defineProperty(a, 'a1', { value: -0, writable: false, configurable: false, enumerable: false, }); Object.defineProperty(a, 'a1', { value: -0, }); // 正常執行 Object.defineProperty(a, 'a1', { value: 0, }); // Uncaught TypeError: Cannot redefine property: a1 } test();
對于數組判斷是否存在的場景,如果想區分+0 和-0,可以使用 ECMAScript 2015 引入的 find 方法,自行控制判斷邏輯,代碼示例如下:
[0].includes(-0); // 不能區分-0 [0].find((val) => Object.is(val, -0)); // 能區分+0和-0
總結
最后來對比下四種算法的區別,區別如下表所示:
隱式轉換 | NaN 和 NaN | +0 和 -0 | |
---|---|---|---|
非嚴格相等(==) | 是 | false | true |
嚴格相等(===) | 否 | false | true |
同值零(includes 等) | 否 | true | true |
同值(Object.is) | 否 | true | false |
JavaScript判斷相等值內容講述完了,希望大家好好學習更多知識。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/128374.html
摘要:如果沒有傳入的話如果是類型,則取否則,取這個方法大致和一樣,除了以下返回返回參考知乎中和區別是什么全面解析中的數據類型與類型轉換規范 有哪些判斷相等性的方法 JavaScript現在提供了三種方法來判斷相等性: ===,三個等號即嚴格相等 ==,兩個等號即寬松相等 Object.is(),ES6中用來判斷相等的方法 判斷相等性的細節 ===(嚴格相等) 被比較的兩個數不會進行類型轉...
摘要:專題系列共計篇,主要研究日常開發中一些功能點的實現,比如防抖節流去重類型判斷拷貝最值扁平柯里遞歸亂序排序等,特點是研究專題之函數組合專題系列第十六篇,講解函數組合,并且使用柯里化和函數組合實現模式需求我們需要寫一個函數,輸入,返回。 JavaScript 專題之從零實現 jQuery 的 extend JavaScritp 專題系列第七篇,講解如何從零實現一個 jQuery 的 ext...
摘要:如果為假值,不傳或者傳入,函數都會返回但是,傳入這個值是完全有可能的,所以這種判斷形勢是不正確的或者使用來判斷也可以原始類型優于封裝類型對象擁有六個原始值基本類型布爾值,數字,字符串,,和對象。 作為一個前端新人,多讀書讀好書,夯實基礎是十分重要的,正如蓋樓房一樣,底層穩固了,才能越壘越高。從開始學習到現在,基礎的讀了紅寶書《JavaScript高級程序設計》,犀牛書《JavaScri...
摘要:數值表示法科學計數法是一種數學術語,將一個數表示為乘以的次方,如光速萬公里每秒,在計算中通常將米做單位,則記為,而在中我們可使用科學計數法表示。以下情況會自動將數值轉為科學計數法表示小數點前的數字多于位。 showImg(https://segmentfault.com/img/bVbhNqT?w=1024&h=683); 因為球是圓的,所以不論發生什么都有可能,對這點我是深信不疑的,...
摘要:等同于等同于其他類型和布爾類型之間的比較如果是布爾類型,則返回的結果。 showImg(https://segmentfault.com/img/bVburFq?w=796&h=398); 前言 JavaScript作為一門弱類型語言,我們在每天的編寫代碼過程中,無時無刻不在應用著值類型轉換,但是很多時候我們只是在單純的寫,并不曾停下腳步去探尋過值類型轉換的內部轉換規則,最近通過閱讀你...
閱讀 561·2023-03-27 18:33
閱讀 750·2023-03-26 17:27
閱讀 647·2023-03-26 17:14
閱讀 603·2023-03-17 21:13
閱讀 537·2023-03-17 08:28
閱讀 1823·2023-02-27 22:32
閱讀 1315·2023-02-27 22:27
閱讀 2199·2023-01-20 08:28