不管是在開發中,仍是面試時,在js中判斷變量是否相等
,都是一個比較常見的問題。比較典型的有,==
和 ===
的區別?判斷變量是否相等有哪些方式?javascript
這裏打算總結一下判斷變量是否相等的方式,以及作一些簡單的分析。前端
判斷變量是否相等,大體有如下一些方式java
==
以及 ===
;toString
方法;ES6
中的Object.is
方法;JSON.stringify
,轉換爲String
類型來比較;==
及 ===
==
爲轉換類型比較運算符,===
爲嚴格比較運算符,在數據類型相同的狀況下,使用==
通常不會形成問題。面試
let num = 5;
let num2 = 5;
num == num2;//true
num === num2;//true
複製代碼
但在數據類型不一致的狀況下,==
會作一些隱性的類型轉換。後端
let num = 5;
let str = '5';
num == str;//true
num === str;//false
'' == false;//true
'' === false;//false
null == undefined;//true
null === undefined;//false
複製代碼
隱性轉換類型能夠帶來一些便利性,但也有可能形成不易發現的bug
,因此仍是更推薦使用===
來進行比較,這也是TS
之因此流行的緣由之一。數組
此外,上面列舉的都是基本數據類型的比較,而在用===
比較引用類型時,會存在必定的侷限性。app
let a = {xx: 1};
let b = a;
a === b;//true
let c = {xx: 1};
let d = {xx: 1};
c === d;//false
複製代碼
在比較引用類型時,===
比較的是變量的引用是否相同,而非值
,當引用不一樣時,就會返回false
。工具
因而可知,===
並非一枚無往不利的銀彈,在比較對象是否相等時,還須要藉助其餘更可靠的方法。ui
前端給後端傳參時,後端有時會要求多個參數,
隔開,Array toString
方法就比較有用了,這一方法也能用做數組比較。spa
let arr = [1,3,5,7,9];
let arr2 = [1,3,5,7,9];
arr.toString() === arr2.toString();//true "1,3,5,7,9"
複製代碼
不過也存在必定的侷限性,不能用來比較二維及以上的數組、不能包含null
、undefined
、object
、function
等,不然容易出錯,以下
[1,3,5,[2,4,6]].toString();//"1,3,5,2,4,6"
[1,null,undefined,'',2].toString();//"1,,,,2"
[{xx:2},window,1,2].toString();//"[object Object],[object Window],1,2"
複製代碼
Object.is
是ES6中新增的方法,與===
很是相似,一樣用做比較兩個值是否相等。
Object.is(1,1);//true
Object.is('str','str');//true
Object.is({},{});//false
複製代碼
不一樣的是在判斷+0
和-0
、NaN
和NaN
時的區別。
+0 === -0 //true
NaN === NaN //false
Object.is(+0, -0) //false
Object.is(NaN, NaN) //true
複製代碼
在處理兼容性問題時,polyfill能夠這麼寫。
if (!Object.is) {
Object.is = function(x, y) {
if (x === y) {
// 針對+0 不等於 -0的狀況
return x !== 0 || 1 / x === 1 / y;
} else {
// 針對NaN的狀況
return x !== x && y !== y;
}
};
}
複製代碼
JSON.stringify
方法用於把對象或者數組轉換爲一個 JSON字符串,得出的字符串即可以用做對象的比較。
let obj = {name: 'lin', age: 24};
let obj2 = {name: 'lin', age: 24};
obj === obj2;//false
JSON.stringify(obj) === JSON.stringify(obj2);//true
複製代碼
JSON.stringify
彌補了===
沒法準確比較對象的侷限,不過它也有必定的侷限性,在遇到undefined
、function
以及symbol
值時會忽略。
另外,值得一提的是利用JSON.parse
、JSON.stringify
可實現對象深拷貝,侷限性同上。
上面介紹的方法各有其用處及侷限,若是要找一個覆蓋更多使用場景的方法,無疑須要本身造輪子
了,不過這裏更推薦underscore
的isEqual
方法,畢竟是現有經得起考驗的。
var eq, deepEq;
eq = function(a, b, aStack, bStack) {
if (a === b) return a !== 0 || 1 / a === 1 / b;
if (a == null || b == null) return false;
if (a !== a) return b !== b;
var type = typeof a;
if (type !== 'function' && type !== 'object' && typeof b != 'object') return false;
return deepEq(a, b, aStack, bStack);
};
deepEq = function(a, b, aStack, bStack) {
if (a instanceof _) a = a._wrapped;
if (b instanceof _) b = b._wrapped;
var className = toString.call(a);
if (className !== toString.call(b)) return false;
switch (className) {
case '[object RegExp]':
case '[object String]':
return '' + a === '' + b;
case '[object Number]':
if ( + a !== +a) return + b !== +b;
return + a === 0 ? 1 / +a === 1 / b: +a === +b;
case '[object Date]':
case '[object Boolean]':
return + a === +b;
case '[object Symbol]':
return SymbolProto.valueOf.call(a) === SymbolProto.valueOf.call(b);
}
var areArrays = className === '[object Array]';
if (!areArrays) {
if (typeof a != 'object' || typeof b != 'object') return false;
var aCtor = a.constructor,
bCtor = b.constructor;
if (aCtor !== bCtor && !(_.isFunction(aCtor) && aCtor instanceof aCtor && _.isFunction(bCtor) && bCtor instanceof bCtor) && ('constructor' in a && 'constructor' in b)) {
return false;
}
}
aStack = aStack || [];
bStack = bStack || [];
var length = aStack.length;
while (length--) {
if (aStack[length] === a) return bStack[length] === b;
}
aStack.push(a);
bStack.push(b);
if (areArrays) {
length = a.length;
if (length !== b.length) return false;
while (length--) {
if (!eq(a[length], b[length], aStack, bStack)) return false;
}
} else {
var keys = _.keys(a),
key;
length = keys.length;
if (_.keys(b).length !== length) return false;
while (length--) {
key = keys[length];
if (! (_.has(b, key) && eq(a[key], b[key], aStack, bStack))) return false;
}
}
aStack.pop();
bStack.pop();
return true;
};
_.isEqual = function(a, b) {
return eq(a, b);
};
複製代碼
_.isEqual(NaN,NaN);//true
_.isEqual(1,'1');//false
_.isEqual({},{});//true
複製代碼
underscore
的isEqual
方法大體如上,感興趣的能夠本身稍加修改,移植到本身的經常使用方法中。
這裏推薦個人前一篇文章,【總結】作一個本身的前端js工具庫,把經常使用方法封裝到本身的工具庫中,能夠便於後續使用。
不同的場景可能有不同的需求,若是隻比較基本數據類型,那麼===
就足夠了,若是想「一勞永逸
」,那麼付出必定的成本使用自定義方法無疑是有必要的。
在平常反覆的開發中,仍是要多多探索吧。