由於在做鍵盤導航組件的項目時,有這樣一個需求,當用戶傳入按鍵字母和網址的映射時,如果和 localStorage 中的不一樣那么就用 localStorage 中存儲的,這個時候就需要比較兩個對象的內容是否相等,但是在 JS 中對象是一種引用類型.
obj1 = {
a: 1
}
obj2 = {
a: 1
}
console.log(obj1 === obj2) // false
即使兩個對象的內容完全相同,因為它們的地址不同,因此 obj1 === obj2
會返回 fasle。
所以自己根據深拷貝時遞歸的思想寫了一個比較兩個對象之間內容是否相同的函數。
function compareObject (obj1, obj2) {
// 遞歸終止條件,當 obj1 或 obj2 不是對象時,此時就可以進行判斷了
if (typeof obj1 !== 'object' || typeof obj2 !== 'object') {
if (obj1 === obj2) {
return true
} else if (obj1 !== obj2) {
return false
}
}
// 獲取對象的自由屬性組成的數組
const obj1PropsArr = Object.getOwnPropertyNames(obj1)
const obj2PropsArr = Object.getOwnPropertyNames(obj2)
// 如果數組的長度不相等,那么說明對象屬性的個數都不同,返回 false
if (obj1PropsArr.length !== obj2PropsArr.length) {
return false
}
// 記錄當前 compareObject 的返回值,默認是 true
let status = true
for (key of obj1PropsArr) {
status = compareObject(obj1[key], obj2[key])
// 關鍵代碼,當 status 為 false 時下面就不用再進行判斷了,說明兩個對象的內容並不相同
// 如果沒有下面這條語句,那么只要對象底層的內容是相同的那么就返回 true
if (!status) {
break
}
}
// 每次 compareObject 執行的返回結果
return status
}
測試代碼:
// 判斷兩個對象的內容相等
const obj1 = {
a: 1,
b: {
c: 2,
d: {
e: 4
}
}
}
const obj2 = {
a: 1,
b: {
c: 2,
d: {
e: 4
}
}
}
console.log(compareObject(obj1, obj2)) // true
// 判斷兩個對象的內容不相等
const obj1 = {
a: 1,
b: {
c: 2,
d: {
e: 4
}
}
}
const obj2 = {
a: 1,
b: {
c: 2,
d: {
e: 5
}
}
}
console.log(compareObject(obj1, obj2)) // false
接下來再來強調一下 compareObject
函數中第 23 行這句關鍵代碼,如果沒有這條語句那么最后的返回結果只會取決於兩個對象最底層屬性(最后一次)的比較結果。
if (!status) {
break
}
例如,我將兩個對象變為下面這樣:
const obj1 = {
a: 1,
b: {
c: 3, // 和 obj2 不相等
d: {
e: 4
}
}
}
const obj2 = {
a: 1,
b: {
c: 2,
d: {
e: 4
}
}
}
console.log(compareObject(obj1, obj2)) // true
可以看到最后的返回結果是 true,因為最后的一次比較是 e 屬性,它們的值是相等的。
上面這樣的寫法應該還有一些情況沒有考慮到,對於我的項目需求而言已經足夠了,如果哪位小伙伴發現了希望可以提出來,然后再將它改進一下,非常感謝。