TypeScript 中嵌套数组比较总是返回 false 的问题解决
在 TypeScript 开发过程中,很多初学者都会遇到一个常见的问题:明明两个嵌套数组的内容完全一致,使用相等运算符比较时却始终返回 false。这是因为 JavaScript/TypeScript 中对于对象和数组的比较,默认是基于引用地址的,而非内容本身。本文将详细解释这个现象的原因,并且给出几种可行的解决方案。
问题现象重现
我们先来看一个典型的示例代码,直观感受这个问题:
// 定义两个内容完全一致的嵌套数组 const arr1 = [[1, 2], [3, 4]]; const arr2 = [[1, 2], [3, 4]]; // 使用相等运算符比较 console.log(arr1 === arr2); // 输出 false console.log(arr1 == arr2); // 输出 false // 即使先赋值再比较,只要不是同一个引用,结果依然是 false const arr3 = arr1; console.log(arr1 === arr3); // 输出 true,因为是同一个引用
从上面的代码可以看到,arr1 和 arr2 的内容完全相同,但比较结果却是 false。这是因为数组属于引用类型,变量存储的是数组在内存中的地址,相等运算符比较的是两个变量存储的地址是否相同,而不是数组的内容。
问题产生的原因
在 TypeScript 和 JavaScript 中,数据类型分为基本类型和引用类型:
- 基本类型(number、string、boolean、null、undefined、symbol、bigint):比较的是值本身,值相同则返回 true。
- 引用类型(对象、数组、函数等):比较的是引用地址,只有两个变量指向同一个内存中的对象/数组时,比较结果才为 true。
嵌套数组本质上是数组的数组,外层数组的每个元素都是内层数组的引用,因此即使是内容相同的嵌套数组,只要不是同一个引用,比较结果必然是 false。
解决方案
要解决嵌套数组比较的问题,我们需要实现基于内容的深度比较,下面介绍几种常用的方法。
方法一:递归深度比较
递归是比较嵌套结构最通用的方法,思路是:先判断两个值是否为数组,如果是数组则遍历每个元素递归比较;如果不是数组则直接比较值是否相等。需要注意处理数组长度不同的情况。
/**
* 深度比较两个数组是否内容完全一致
* @param arr1 第一个数组
* @param arr2 第二个数组
* @returns 两个数组内容完全一致则返回 true,否则返回 false
*/
function deepCompareArray(arr1: any[], arr2: any[]): boolean {
// 如果两者都不是数组,直接比较值
if (!Array.isArray(arr1) || !Array.isArray(arr2)) {
return arr1 === arr2;
}
// 长度不同则肯定不相等
if (arr1.length !== arr2.length) {
return false;
}
// 遍历每个元素递归比较
for (let i = 0; i < arr1.length; i++) {
const item1 = arr1[i];
const item2 = arr2[i];
// 如果元素是数组,递归比较
if (Array.isArray(item1) && Array.isArray(item2)) {
if (!deepCompareArray(item1, item2)) {
return false;
}
} else {
// 非数组元素直接比较值
if (item1 !== item2) {
return false;
}
}
}
return true;
}
// 测试示例
const testArr1 = [[1, 2], [3, 4]];
const testArr2 = [[1, 2], [3, 4]];
const testArr3 = [[1, 2], [3, 5]];
console.log(deepCompareArray(testArr1, testArr2)); // 输出 true
console.log(deepCompareArray(testArr1, testArr3)); // 输出 false方法二:转换为 JSON 字符串比较
这种方法思路比较简单,先把两个数组通过 JSON.stringify 转换为 JSON 字符串,再比较字符串是否相等。不过这种方法有局限性,比如数组元素的顺序必须一致,且不能包含函数、undefined 等无法被 JSON 序列化的内容。
/**
* 通过 JSON 序列化比较两个数组是否内容一致
* @param arr1 第一个数组
* @param arr2 第二个数组
* @returns 两个数组序列化后的字符串一致则返回 true,否则返回 false
*/
function compareArrayByJSON(arr1: any[], arr2: any[]): boolean {
// 先判断长度,减少不必要的序列化操作
if (arr1.length !== arr2.length) {
return false;
}
return JSON.stringify(arr1) === JSON.stringify(arr2);
}
// 测试示例
const jsonArr1 = [[1, 2], [3, 4]];
const jsonArr2 = [[1, 2], [3, 4]];
const jsonArr3 = [[1, 2], [3, 5]];
console.log(compareArrayByJSON(jsonArr1, jsonArr2)); // 输出 true
console.log(compareArrayByJSON(jsonArr1, jsonArr3)); // 输出 false
// 注意:如果数组包含序列化会丢失的内容,这种方法会失效
const arrWithFunc = [() => {}, [1, 2]];
const arrWithFunc2 = [() => {}, [1, 2]];
console.log(compareArrayByJSON(arrWithFunc, arrWithFunc2)); // 输出 true,但实际数组内容并不相同方法三:使用第三方库实现深度比较
如果项目中已经有 lodash 这样的工具库,也可以直接使用库提供的深度比较方法,避免重复造轮子。以 lodash 的 isEqual 方法为例:
// 先安装 lodash:npm install lodash @types/lodash
import { isEqual } from 'lodash';
const lodashArr1 = [[1, 2], [3, 4]];
const lodashArr2 = [[1, 2], [3, 4]];
const lodashArr3 = [[1, 2], [3, 5]];
console.log(isEqual(lodashArr1, lodashArr2)); // 输出 true
console.log(isEqual(lodashArr1, lodashArr3)); // 输出 falselodash 的 isEqual 方法支持各种复杂数据结构的深度比较,包括对象、数组、日期、正则等,适用场景更全面,适合在大型项目中使用。
方案选择建议
不同的方案有各自的适用场景,可以根据实际需求选择:
- 如果只需要比较纯数据的嵌套数组,没有特殊类型,且项目不想引入额外依赖,可以选择递归比较或者 JSON 序列化比较。
- 如果数组可能包含复杂类型(如对象、日期等),或者需要比较的内容不只是数组,建议使用 lodash 这类成熟的工具库,避免自己实现的比较逻辑出现遗漏。
- JSON 序列化比较方法实现最简单,但要注意其局限性,不要用于包含不可序列化内容的数组比较。
通过上述方法,就可以解决 TypeScript 中嵌套数组比较始终返回 false 的问题,实现基于内容的准确比较。
TypeScript嵌套数组比较引用类型深度比较lodash_isEqual 本作品最后修改时间:2026-05-22 14:29:45