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.