判断对象是否相等的方法,==与 isEqual

本文探讨了Objective-C中如何比较对象的内存地址及内容,重点介绍了isEqualToString与isEqual方法的区别,以及如何通过重写isEqual方法实现自定义类的对象内容比较。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


  • == 比较两个对象的内存地址

  • isEqualToString: 比较两个字符串的内容

  • isEqual: 默认情况下是比较两个对象的内存地址,但是有一些系统自带的类(比如Foundation中的NSString,NSArray等)重写了这个方法,改变了这个方法的判断规则(一般改为比较两个对象的内容,不是内存地址)

数组NSArray中的containsObject:,indexOfObject:方法就是利用isEqual来比较的,所以数组中的字符串内容一样,也会被认为是一样的

- (void)test1
{
   NSString *string1 = @"jack";
   NSString *string2 = [NSString stringWithFormat:@"jack"];

//理论上存储在内存不同区域,为不同对象,但系统重写后改成了比较内容
   NSLog(@"%p %p", string1, string2);

   NSLog(@"string1 == string2 -> %zd", string1 == string2); // 结果为0

   NSLog(@"[string1 isEqualToString:string2] -> %zd", [string1 isEqualToString:string2]); // 结果为1

   NSLog(@"[string1 isEqual:string2] -> %zd", [string1 isEqual:string2]); // 结果为1

}
复制代码

同理下面的两个数组并不是同一个,但是内容相同,因此会被判定为相同

- (void)test2
{
    NSString *string1 = [NSString stringWithFormat:@"111"];
    NSString *string2 = [NSString stringWithFormat:@"222"];
    //两个存储不同对象的数组,但内容是相同的
    NSArray *array1 = @[string1, @"222", @"333"];
    NSArray *array2 = @[@"111", string2, @"333"];
    
    NSArray *array = @[array1, array2];
    
    NSLog(@"%zd", [array indexOfObject:array2]);//结果为0
}
复制代码

如果有两个内容相同的MYPerson对象,则会被认为是不同的,因为此时是对内存地址进行比较,看是不是同一个对象

//没有重写isEqual
- (void)test3
{
    MYPerson *p1 = [[MYPerson alloc] init];
    p1.age = 20;
    p1.no = 30;
    
    MYPerson *p2 = [[MYPerson alloc] init];
    p2.age = 20;
    p2.no = 30;
    
    NSLog(@"%p %p", p1, p2);
    NSLog(@"p1 == p2 -> %zd", p1 == p2); // 0
    NSLog(@"[p1 isEqual:p2] -> %zd", [p1 isEqual:p2]); // 0
}
复制代码

如果希望MYPerson也能像系统的类NSString一样,能够对内容相同的两个不同对象也认定为相同,需要重写isEqual方法

//重写后
- (void)test3
{
    MYPerson *p1 = [[MYPerson alloc] init];
    p1.age = 20;
    p1.no = 30;
    
    MYPerson *p2 = [[MYPerson alloc] init];
    p2.age = 20;
    p2.no = 30;

    NSArray *array = @[@"2", @"6", p1, @"111"];
    
    NSLog(@"%zd", [array indexOfObject:p2]);//结果为2
}
复制代码

MYPerson中重写代码如下:


#import <Foundation/Foundation.h>

@class MYCar;

@interface MYPerson : NSObject
@property (nonatomic, assign) NSInteger age;
@property (nonatomic, assign) NSInteger no;
@property (nonatomic, copy) NSString *name;
@property (nonatomic, strong) MYCar *car;

- (BOOL)isEqualToPerson:(MYPerson *)person;
@end

复制代码
#import "MYPerson.h"
#import "MYCar.h"

/*
 一旦重写了isEqual:方法,最好重写hash方法,而且要遵守以下原则:
 1.isEqual:返回YES的2个对象,hash值一定要一样
 2.hash值一样的2个对象,isEqual:返回不一定是YES
 */

@implementation MYPerson

- (NSUInteger)hash
{
    return self.age + self.no + self.name.hash + self.car.hash;
}

- (BOOL)isEqual:(MYPerson *)object
{
    return [self isEqualToPerson:object];
}

- (BOOL)isEqualToPerson:(MYPerson *)person
{
    // 如果是完全相同的对象,就省去后面的判断
    if (self == person) return YES;
    
    // 如果object的类型不对,就不需要比较
    if (![person isKindOfClass:self.class]) return NO;
    
    // 基本数据类型
    BOOL result = (self.age == person.age && self.no == person.no);
    if (result == NO) return result;
    
    // 对象类型,两个对象为nil时isEqual:的结果为0(NO),所以需要专门处理
    if (self.name || person.name) {
        if (![self.name isEqual:person.name]) return NO;
    }
    
    if (self.car || person.car) {
        if (![self.car isEqual:person.car]) return NO;
    }
    
    return YES;
}

@end

复制代码
<think>我们正在讨论的是在Vue3中判断两个对象是否相等的问题。在JavaScript中,对象是引用类型,直接比较两个对象(如`obj1 === obj2`)是比较它们的引用(即内存地址是否相同,而不是它们的内容是否相同。因此,我们需要其他方法判断两个对象的内容是否相等。 在Vue3中,我们可以使用以下方法: 1. **手动比较**:遍历对象的属性,逐一比较。这种方法适用于简单的对象,但要注意嵌套对象的情况。 2. **使用JSON.stringify**:将两个对象转换成JSON字符串,然后比较字符串是否相等。这种方法简单,但存在局限性(例如,属性顺序改变、函数属性等)。 3. **使用第三方库**:如lodash的`isEqual`方法,这是一个深度比较的方法,可以处理复杂的对象和数组。 考虑到Vue3本身并没有提供专门的方法来比较两个对象是否相等,我们通常使用第三方库或者自己实现深度比较。 下面我们分别展示这三种方法: **方法1:手动比较(浅比较)** 如果对象只有一层,我们可以使用浅比较。例如: ```javascript function shallowEqual(obj1, obj2) { const keys1 = Object.keys(obj1); const keys2 = Object.keys(obj2); if (keys1.length !== keys2.length) { return false; } for (let key of keys1) { if (obj1[key] !== obj2[key]) { return false; } } return true; } ``` **方法2:使用JSON.stringify** ```javascript function isEqual(obj1, obj2) { return JSON.stringify(obj1) === JSON.stringify(obj2); } ``` 注意:这种方法要求对象的属性顺序一致,并且不能包含循环引用。如果对象中有`undefined`、函数或Symbol值,在序列化过程中会被忽略(或转换为`null`),因此可能导致不准确。 **方法3:使用lodash的isEqual方法** 首先安装lodash: ```bash npm install lodash ``` 然后在Vue组件中使用: ```javascript import { isEqual } from 'lodash'; // 使用 if (isEqual(obj1, obj2)) { // 相等 } ``` 在Vue3的响应式系统中,我们有时需要比较两个响应式对象。由于Vue3的响应式对象是通过Proxy包装的,但上述方法(尤其是lodash的`isEqual`)仍然可以正常工作,因为它们比较的是对象的实际值。 另外,Vue3的`reactive`或`ref`创建的响应式对象,我们也可以将其转换为普通对象再进行比较(使用`toRaw`函数),但这通常不是必须的,因为深度比较函数会读取对象的属性值,而Proxy会正常返回这些值。 **总结**:推荐使用lodash的`isEqual`进行深度比较,因为它处理了各种边界情况(如嵌套对象、数组、日期、正则表达式等)且稳定可靠。 下面是一个在Vue3组件中使用的例子: ```vue <script setup> import { reactive } from 'vue'; import { isEqual } from 'lodash'; const obj1 = reactive({ a: 1, b: { c: 2 } }); const obj2 = reactive({ a: 1, b: { c: 2 } }); console.log(isEqual(obj1, obj2)); // true </script> ``` 如果不想引入整个lodash,也可以只安装`lodash.isequal`: ```bash npm install lodash.isequal ``` 然后引入: ```javascript import isEqual from 'lodash.isequal'; ``` 这样,我们就可以在Vue3中方便地判断两个对象是否相等了。</think>在 Vue 3 中判断两个对象是否相等需要特别注意:JavaScript 中对象是引用类型,直接使用 `===` 比较的是内存地址而非内容。以下是完整的解决方案: ### 方法 1:深度比较函数(推荐) ```javascript function deepEqual(obj1, obj2) { // 类型不同 if (typeof obj1 !== typeof obj2) return false // 基本类型直接比较 if (obj1 === obj2 || Number.isNaN(obj1) && Number.isNaN(obj2)) return true // 数组比较 if (Array.isArray(obj1)) { if (!Array.isArray(obj2) || obj1.length !== obj2.length) return false return obj1.every((item, i) => deepEqual(item, obj2[i])) } // 对象比较 if (typeof obj1 === 'object' && obj1 !== null) { const keys1 = Object.keys(obj1) const keys2 = Object.keys(obj2) if (keys1.length !== keys2.length) return false return keys1.every(key => deepEqual(obj1[key], obj2[key])) } return false } ``` ### 方法 2:JSON.stringify(简单对象) ```javascript const isEqual = (a, b) => JSON.stringify(a) === JSON.stringify(b) ``` ⚠️ 局限性: 1. 无法处理`undefined`和函数属性 2. 属性顺序敏感 3. 不能比较循环引用对象 ### 方法 3:使用 Lodash(生产环境推荐) ```bash npm install lodash ``` ```javascript import { isEqual } from 'lodash' // 响应式对象可直接比较 const obj1 = reactive({ a: 1, b: { c: 2 } }) const obj2 = reactive({ a: 1, b: { c: 2 } }) console.log(isEqual(obj1, obj2)) // true ``` ### Vue 3 响应式对象注意事项 1. **直接比较问题**: ```javascript const a = reactive({ x: 1 }) const b = reactive({ x: 1 }) console.log(a === b) // false(比较的是Proxy实例) ``` 2. **解决方案**: ```javascript // 方法1:比较原始值 console.log(isEqual(toRaw(a), toRaw(b))) // 方法2:直接使用lodash(自动解包Proxy) console.log(isEqual(a, b)) ``` ### 性能优化建议 1. 对于浅层对象:使用`Object.keys()` + `every()`组合 ```javascript const shallowEqual = (a, b) => Object.keys(a).length === Object.keys(b).length && Object.keys(a).every(k => a[k] === b[k]) ``` 2. 使用缓存:对频繁比较的对象生成哈希值 ```javascript import { createHash } from 'crypto' const getHash = obj => createHash('md5').update(JSON.stringify(obj)).digest('hex') ``` ### 在 Vue 组件中的使用示例 ```vue <script setup> import { ref, reactive } from 'vue' import { isEqual } from 'lodash' const userA = reactive({ name: 'John', permissions: ['read', 'write'] }) const userB = ref({ ...userA }) watch([userA, userB], ([newA, newB]) => { if (!isEqual(newA, newB)) { console.log('检测到用户数据变化') } }) </script> ``` ### 不同场景推荐方案 | 场景 | 推荐方案 | 原因 | |------|----------|------| | 简单对象 | `JSON.stringify` | 实现简单,无依赖 | | 深层嵌套对象 | Lodash `isEqual` | 处理边界情况完善 | | 高频比较 | 自定义哈希函数 | 性能最优 | | 响应式对象 | Lodash + `toRaw` | 避免Proxy干扰 | > 提示:对于表单状态对比等常见场景,VueUse 库的 [`useEqual`](https://vueuse.org/shared/useEqual/) 工具提供了开箱即用的解决方案。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值