TIP
在js中,不能使用===
来判断Object,Array,Set,Map两个是否相等
js
function isFunction(a) {
return Object.prototype.toString.call(a) === '[object Function]';
}
function eq(a, b, aStack, bStack) {
// 1/+0 !==1/-0
if (a === b) return a !== 0 || 1 / a === 1 / b;
// null 和 undefined 在严格模式下只等于自己
if (a == null || b == null) return false;
// NaN !== NaN
if (a !== a) return b !== b;
// 如果a不是函数和引用类型 b也不是引用类型即 a,b都是基础类型, 那么a不等于b
const type = typeof a;
if (type !== 'function' && type !== 'object' && typeof b !== 'object')
return false;
return deepEq(a, b, aStack, bStack);
}
function deepEq(a, b, aStack, bStack) {
let className = Object.prototype.toString.call(a);
console.log(className);
// 如果两个类型不同则不等
if (className !== Object.prototype.toString.call(b)) return false;
switch (className) {
// 正则 和 普通字符串 和 包装型字符串 利用隐式类型转换转为字符串比较
// new String('test') !== 'test'
// '' + new String('test') !== '' + 'test'
case '[object RegExp]':
case '[object String]':
return '' + a === '' + b;
case '[object Number]':
// NaN !== NaN +NaN -> NaN
if (+a !== +a) return +b !== +b;
// +0 !== -0
return +a === 0 ? 1 / +a === 1 / b : +a === +b;
// 日期 布尔值 隐式转换为数字比较
case '[object Date]':
case '[object Boolean]':
return +a === +b;
case '[object Symbol]':
// Symbol 类型不会隐式转换为原始值
return (
Symbol.prototype.valueOf.call(a) ===
Symbol.prototype.valueOf.call(b)
);
}
const areArrays = className === '[object Array]';
if (!areArrays) {
// 不是数组 a或b不是object(引用类型)
if (typeof a != 'object' || typeof b != 'object') return false;
const aCtor = a.constructor,
bCtor = b.constructor;
// a b 不是由同一构造函数实例化 且 ab构造函数是函数且aCtor不等于Object 且 ab上存在constuctor属性 则ab不等
// 不是 对象也不是数组
// obj = {name:'test'} obj.constructor instanceof obj.constructor -> true
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 || [];
let length = aStack.length;
while (length--) {
if (aStack[length] === a) return bStack[length] === b;
}
aStack.push(a);
bStack.push(b);
if (areArrays) {
length = a.length;
// 数组长度不等则ab不等
if (length !== b.length) return false;
// 比对数组值
while (length--) {
if (!eq(a[length], b[length], aStack, bStack)) return false;
}
} else {
const _keys = Object.keys(a);
let key;
length = _keys.length;
if (length !== Object.keys(b).length) return false;
while (length--) {
key = _keys[length];
if (!(b.hasOwnProperty(key) && eq(a[key], b[key], aStack, bStack)))
return false;
}
}
aStack.pop();
bStack.pop();
return true;
}