Please implement an isEqual function that performs deep comparison. Deep comparison is used to compare whether two different objects have the same values.
const object = { a: 1, b: [2, 3] };
const other = { a: 1, b: [2, 3] };
isEqual(object, other);
// => true
console.log(object === other)
// => false
function isEqual(value, other) {
// 先處理兩個值都是原始型別 (primitive type) 的狀況
if (typeof value !== "object" && typeof other !== "object") {
// 在 JavaScript 中,NaN 是唯一不等於自己的值,所以要特別處理
if (Number.isNaN(value) && Number.isNaN(other)) {
return true;
}
return value === other;
}
// null 的型別是 object,所以我們需要額外處理 null 的狀況
if (value === null && other === null) {
return true;
}
// 假如一個是原始型別,另一個是物件型別,那就回傳 false
if (typeof value !== typeof other) {
return false;
}
// 假如通過以上的條件,代表兩個值都是物件型別,
// 所以我們先比較兩個物件,如果是來自同個址 (reference) 則回傳 true
if (value === other) {
return true;
}
// 接著,當這兩個物件都是陣列時的狀況
if (Array.isArray(value) && Array.isArray(other)) {
// 如果兩個陣列長度不同,則回傳 false
if (value.length !== other.length) {
return false;
}
// 迭代陣列中的每個值,然後遞迴地用 isEqual 比較兩個值
for (let i = 0; i < value.length; i++) {
if (!isEqual(value[i], other[i])) {
return false;
}
}
return true;
}
// 只有一個是陣列,但另一個不適的狀況,則回傳 false
// 因為上面的 && 沒有成立,代表不會兩個都是陣列,這邊用 || 就能判斷是否有一個是陣列
if (Array.isArray(value) || Array.isArray(other)) {
return false;
}
// 如果上面的條件中都沒有回傳,剩下的可能性是兩個值都是物件
// 先檢查兩個物件的 key 一樣多,不一樣多代表兩個物件一定不同
if (Object.keys(value).length !== Object.keys(other).length) {
return false;
}
// 假如兩個物件有一樣多的 key 透過 Object.entires 迭代過第一個物件
for (const [key, val] of Object.entries(value)) {
// 如果第一個物件中的某個 key 不存在於第二個物件,代表兩者不同
if (!(key in other)) {
return false;
}
// 如果第一個物件中的鍵值對與第二個的不同,也代表兩個物件不同
// 切記,因為值可能也是某個物件,所以要用 isEqual 遞迴地檢查是否兩個值一樣
if (!isEqual(val, other[key])) {
return false;
}
}
return true
}