Skip to content

isEqual

深度比較兩個值是否相等,支持對象、數組、基本類型等。

基礎用法

typescript
import { isEqual } from 'radash'

console.log(isEqual(1, 1))                    // true
console.log(isEqual('hello', 'hello'))        // true
console.log(isEqual([1, 2, 3], [1, 2, 3]))   // true
console.log(isEqual({ a: 1 }, { a: 1 }))     // true
console.log(isEqual(1, '1'))                  // false

語法

typescript
function isEqual(a: any, b: any): boolean

參數

  • a (any): 第一個要比較的值
  • b (any): 第二個要比較的值

返回值

返回一個布爾值,表示兩個值是否深度相等。

示例

基本類型比較

typescript
import { isEqual } from 'radash'

// 數字
console.log(isEqual(1, 1))                    // true
console.log(isEqual(1, 2))                    // false
console.log(isEqual(1, '1'))                  // false
console.log(isEqual(0, -0))                   // true
console.log(isEqual(NaN, NaN))                // true

// 字符串
console.log(isEqual('hello', 'hello'))        // true
console.log(isEqual('hello', 'world'))        // false
console.log(isEqual('', ''))                  // true

// 布爾值
console.log(isEqual(true, true))              // true
console.log(isEqual(false, false))            // true
console.log(isEqual(true, false))             // false

// null 和 undefined
console.log(isEqual(null, null))              // true
console.log(isEqual(undefined, undefined))    // true
console.log(isEqual(null, undefined))         // false

數組比較

typescript
import { isEqual } from 'radash'

// 簡單數組
console.log(isEqual([1, 2, 3], [1, 2, 3]))   // true
console.log(isEqual([1, 2, 3], [1, 2]))      // false
console.log(isEqual([1, 2, 3], [1, 3, 2]))   // false

// 嵌套數組
console.log(isEqual([[1, 2], [3, 4]], [[1, 2], [3, 4]])) // true
console.log(isEqual([[1, 2], [3, 4]], [[1, 2], [3, 5]])) // false

// 空數組
console.log(isEqual([], []))                  // true
console.log(isEqual([1], []))                 // false

// 混合類型數組
console.log(isEqual([1, 'hello', true], [1, 'hello', true])) // true
console.log(isEqual([1, 'hello', true], [1, 'hello', false])) // false

對象比較

typescript
import { isEqual } from 'radash'

// 簡單對象
console.log(isEqual({ a: 1, b: 2 }, { a: 1, b: 2 })) // true
console.log(isEqual({ a: 1, b: 2 }, { b: 2, a: 1 })) // true (屬性順序不重要)
console.log(isEqual({ a: 1, b: 2 }, { a: 1, b: 3 })) // false

// 嵌套對象
console.log(isEqual(
  { user: { name: 'Alice', age: 25 } },
  { user: { name: 'Alice', age: 25 } }
)) // true

console.log(isEqual(
  { user: { name: 'Alice', age: 25 } },
  { user: { name: 'Bob', age: 25 } }
)) // false

// 空對象
console.log(isEqual({}, {}))                  // true
console.log(isEqual({ a: 1 }, {}))           // false

復雜對象比較

typescript
import { isEqual } from 'radash'

const obj1 = {
  id: 1,
  name: 'Alice',
  profile: {
    email: 'alice@example.com',
    address: {
      city: 'Beijing',
      country: 'China'
    },
    preferences: {
      theme: 'dark',
      notifications: true
    }
  },
  hobbies: ['reading', 'swimming'],
  metadata: {
    createdAt: new Date('2023-01-01'),
    tags: ['user', 'active']
  }
}

const obj2 = {
  id: 1,
  name: 'Alice',
  profile: {
    email: 'alice@example.com',
    address: {
      city: 'Beijing',
      country: 'China'
    },
    preferences: {
      theme: 'dark',
      notifications: true
    }
  },
  hobbies: ['reading', 'swimming'],
  metadata: {
    createdAt: new Date('2023-01-01'),
    tags: ['user', 'active']
  }
}

console.log(isEqual(obj1, obj2)) // true

函數比較

typescript
import { isEqual } from 'radash'

const func1 = (x: number) => x * 2
const func2 = (x: number) => x * 2
const func3 = (x: number) => x + 2

console.log(isEqual(func1, func1))            // true (相同引用)
console.log(isEqual(func1, func2))            // false (不同引用)
console.log(isEqual(func1, func3))            // false

日期比較

typescript
import { isEqual } from 'radash'

const date1 = new Date('2023-01-01T00:00:00Z')
const date2 = new Date('2023-01-01T00:00:00Z')
const date3 = new Date('2023-01-02T00:00:00Z')

console.log(isEqual(date1, date2))            // true
console.log(isEqual(date1, date3))            // false
console.log(isEqual(date1, '2023-01-01'))    // false

正則表達式比較

typescript
import { isEqual } from 'radash'

const regex1 = /hello/i
const regex2 = /hello/i
const regex3 = /world/i

console.log(isEqual(regex1, regex1))         // true (相同引用)
console.log(isEqual(regex1, regex2))         // false (不同引用)
console.log(isEqual(regex1, regex3))         // false

特殊值比較

typescript
import { isEqual } from 'radash'

// NaN 比較
console.log(isEqual(NaN, NaN))                // true
console.log(isEqual(NaN, 0))                  // false

// Infinity 比較
console.log(isEqual(Infinity, Infinity))      // true
console.log(isEqual(-Infinity, -Infinity))    // true
console.log(isEqual(Infinity, -Infinity))     // false

// 零值比較
console.log(isEqual(0, -0))                   // true
console.log(isEqual(0, 0))                    // true

循環引用處理

typescript
import { isEqual } from 'radash'

const obj1: any = { a: 1 }
obj1.self = obj1

const obj2: any = { a: 1 }
obj2.self = obj2

// 注意:循環引用可能導致無限遞歸
// 在實際使用中需要小心處理
console.log(isEqual(obj1, obj2))              // 可能為 true 或拋出錯誤

類型安全比較

typescript
import { isEqual } from 'radash'

// 不同類型的基本值
console.log(isEqual(1, '1'))                  // false
console.log(isEqual(true, 1))                 // false
console.log(isEqual(null, undefined))         // false
console.log(isEqual([], {}))                  // false

// 相同類型的不同值
console.log(isEqual(1, 2))                    // false
console.log(isEqual('hello', 'world'))        // false
console.log(isEqual(true, false))             // false

實際應用場景

typescript
import { isEqual } from 'radash'

// 表單數據比較
function hasFormChanged(originalData: any, currentData: any) {
  return !isEqual(originalData, currentData)
}

const originalForm = {
  name: 'Alice',
  email: 'alice@example.com',
  preferences: {
    theme: 'dark',
    notifications: true
  }
}

const currentForm = {
  name: 'Alice',
  email: 'alice@example.com',
  preferences: {
    theme: 'light', // 改變了
    notifications: true
  }
}

console.log(hasFormChanged(originalForm, currentForm)) // true

配置比較

typescript
import { isEqual } from 'radash'

function hasConfigChanged(oldConfig: any, newConfig: any) {
  return !isEqual(oldConfig, newConfig)
}

const oldConfig = {
  server: {
    port: 3000,
    host: 'localhost'
  },
  database: {
    url: 'postgresql://localhost:5432/mydb',
    pool: {
      min: 1,
      max: 10
    }
  }
}

const newConfig = {
  server: {
    port: 3000,
    host: 'localhost'
  },
  database: {
    url: 'postgresql://localhost:5432/mydb',
    pool: {
      min: 2, // 改變了
      max: 10
    }
  }
}

console.log(hasConfigChanged(oldConfig, newConfig)) // true

狀態比較

typescript
import { isEqual } from 'radash'

function hasStateChanged(oldState: any, newState: any) {
  return !isEqual(oldState, newState)
}

const oldState = {
  user: {
    id: 1,
    name: 'Alice',
    isLoggedIn: true
  },
  settings: {
    theme: 'dark',
    language: 'en'
  }
}

const newState = {
  user: {
    id: 1,
    name: 'Alice',
    isLoggedIn: true
  },
  settings: {
    theme: 'light', // 改變了
    language: 'en'
  }
}

console.log(hasStateChanged(oldState, newState)) // true

緩存鍵比較

typescript
import { isEqual } from 'radash'

class Cache {
  private cache = new Map()

  get(key: any) {
    for (const [cachedKey, value] of this.cache) {
      if (isEqual(cachedKey, key)) {
        return value
      }
    }
    return undefined
  }

  set(key: any, value: any) {
    this.cache.set(key, value)
  }
}

const cache = new Cache()
const params1 = { userId: 1, filter: 'active' }
const params2 = { userId: 1, filter: 'active' }

cache.set(params1, 'cached data')
console.log(cache.get(params2)) // 'cached data' (因為 isEqual(params1, params2) 為 true)

注意事項

  1. 深度比較: 遞歸比較所有嵌套屬性
  2. 類型嚴格: 不同類型的基本值不相等
  3. 引用比較: 函數和正則表達式按引用比較
  4. 循環引用: 可能導致無限遞歸
  5. 性能: 對於大型對象,比較可能較慢

與其他方法的區別

  • ===: 嚴格相等,不進行深度比較
  • ==: 寬松相等,會進行類型轉換
  • isEqual(): radash提供的深度比較方法

實際應用場景

  1. 狀態管理: 比較應用狀態變化
  2. 表單驗證: 檢測表單數據是否改變
  3. 緩存管理: 比較緩存鍵
  4. 配置管理: 檢測配置變化
  5. 測試: 深度比較測試結果

Released under the MIT License.