Search K
Appearance
Appearance
📊 SEO元描述:2024年最新JavaScript数组高级操作教程,详解数组去重5种方法、数组扁平化实现、多维数组处理技巧。包含完整代码示例和性能对比,适合高级前端开发者掌握JavaScript数组操作技巧。
核心关键词:JavaScript数组高级操作2024、数组去重方法、数组扁平化、多维数组处理、JavaScript数组技巧
长尾关键词:JavaScript数组去重怎么实现、数组扁平化有几种方法、JavaScript多维数组怎么处理、数组去重性能对比
通过本节JavaScript数组高级操作,你将系统性掌握:
数组去重是什么?这是移除数组中重复元素,保留唯一值的操作。数组去重是JavaScript开发中的常见需求,也是面试和实际开发中的重要技能。
💡 学习建议:理解不同去重方法的适用场景和性能特点,选择最合适的方案
Set去重法是最简洁高效的去重方式:
// 🎉 使用Set实现数组去重
function uniqueWithSet(arr) {
return [...new Set(arr)];
}
// 基本类型去重
const numbers = [1, 2, 2, 3, 3, 3, 4, 5, 5];
console.log('原数组:', numbers);
console.log('Set去重:', uniqueWithSet(numbers)); // [1, 2, 3, 4, 5]
const strings = ['a', 'b', 'b', 'c', 'c', 'a'];
console.log('字符串去重:', uniqueWithSet(strings)); // ['a', 'b', 'c']
// 🔴 特殊值处理
const specialValues = [1, '1', true, 1, NaN, NaN, null, null, undefined, undefined];
console.log('特殊值去重:', uniqueWithSet(specialValues));
// [1, '1', true, NaN, null, undefined]
// Set的优势:
// 1. 语法简洁
// 2. 性能优秀 O(n)
// 3. 正确处理NaN
// 4. 保持插入顺序
// 性能测试
function performanceTest() {
const largeArray = [];
for (let i = 0; i < 100000; i++) {
largeArray.push(Math.floor(Math.random() * 10000));
}
console.time('Set去重');
const result = uniqueWithSet(largeArray);
console.timeEnd('Set去重');
console.log('原数组长度:', largeArray.length);
console.log('去重后长度:', result.length);
}
// performanceTest();// 🎉 使用filter + indexOf实现去重
function uniqueWithFilter(arr) {
return arr.filter((item, index) => arr.indexOf(item) === index);
}
// 基本使用
const numbers = [1, 2, 2, 3, 3, 3, 4, 5, 5];
console.log('filter去重:', uniqueWithFilter(numbers)); // [1, 2, 3, 4, 5]
// 🔴 NaN的问题
const withNaN = [1, 2, NaN, 3, NaN, 4];
console.log('filter处理NaN:', uniqueWithFilter(withNaN)); // [1, 2, NaN, 3, NaN, 4] ❌ NaN无法去重
// 改进版本:处理NaN
function uniqueWithFilterImproved(arr) {
const seen = [];
return arr.filter(item => {
if (Number.isNaN(item)) {
if (!seen.some(Number.isNaN)) {
seen.push(item);
return true;
}
return false;
}
return arr.indexOf(item) === arr.lastIndexOf(item) || arr.indexOf(item) === arr.indexOf(item);
});
}
// 更简单的改进版本
function uniqueWithIncludes(arr) {
const result = [];
for (const item of arr) {
if (!result.includes(item)) {
result.push(item);
}
}
return result;
}
console.log('includes去重:', uniqueWithIncludes(withNaN)); // [1, 2, NaN, 3, 4] ✅ 正确处理NaN// 🎉 使用reduce实现去重
function uniqueWithReduce(arr) {
return arr.reduce((unique, item) => {
return unique.includes(item) ? unique : [...unique, item];
}, []);
}
// 性能优化版本(避免扩展运算符)
function uniqueWithReduceOptimized(arr) {
return arr.reduce((unique, item) => {
if (!unique.includes(item)) {
unique.push(item);
}
return unique;
}, []);
}
// 使用Map优化的reduce版本
function uniqueWithReduceMap(arr) {
const map = new Map();
return arr.reduce((unique, item) => {
if (!map.has(item)) {
map.set(item, true);
unique.push(item);
}
return unique;
}, []);
}
// 测试
const testArray = [1, 2, 2, 3, 3, 3, 4, NaN, NaN, null, null];
console.log('reduce去重:', uniqueWithReduce(testArray));
console.log('reduce优化版:', uniqueWithReduceOptimized(testArray));
console.log('reduce+Map版:', uniqueWithReduceMap(testArray));// 🎉 使用Map实现去重
function uniqueWithMap(arr) {
const map = new Map();
const result = [];
for (const item of arr) {
if (!map.has(item)) {
map.set(item, true);
result.push(item);
}
}
return result;
}
// 更简洁的Map版本
function uniqueWithMapSimple(arr) {
const map = new Map();
arr.forEach(item => map.set(item, item));
return [...map.values()];
}
// 测试
const testArray = [1, 2, 2, 3, 3, 3, 4, NaN, NaN, null, null, undefined, undefined];
console.log('Map去重:', uniqueWithMap(testArray));
console.log('Map简洁版:', uniqueWithMapSimple(testArray));// 🎉 对象数组去重
function uniqueObjectsBy(arr, key) {
const seen = new Set();
return arr.filter(item => {
const value = item[key];
if (seen.has(value)) {
return false;
}
seen.add(value);
return true;
});
}
// 多字段去重
function uniqueObjectsByMultipleKeys(arr, keys) {
const seen = new Set();
return arr.filter(item => {
const signature = keys.map(key => item[key]).join('|');
if (seen.has(signature)) {
return false;
}
seen.add(signature);
return true;
});
}
// 深度对象去重
function uniqueObjectsDeep(arr) {
const seen = new Set();
return arr.filter(item => {
const signature = JSON.stringify(item);
if (seen.has(signature)) {
return false;
}
seen.add(signature);
return true;
});
}
// 测试对象去重
const users = [
{ id: 1, name: 'Alice', age: 25 },
{ id: 2, name: 'Bob', age: 30 },
{ id: 1, name: 'Alice', age: 25 }, // 重复
{ id: 3, name: 'Charlie', age: 35 },
{ id: 2, name: 'Bob', age: 31 } // id重复但age不同
];
console.log('按id去重:', uniqueObjectsBy(users, 'id'));
console.log('按id和name去重:', uniqueObjectsByMultipleKeys(users, ['id', 'name']));
console.log('深度去重:', uniqueObjectsDeep(users));// 🔴 数组去重方法性能对比
function performanceComparison() {
// 创建测试数据
const createTestData = (size) => {
const arr = [];
for (let i = 0; i < size; i++) {
arr.push(Math.floor(Math.random() * (size / 2))); // 50%重复率
}
return arr;
};
const testData = createTestData(100000);
// 测试各种方法
const methods = {
'Set方法': (arr) => [...new Set(arr)],
'filter+indexOf': (arr) => arr.filter((item, index) => arr.indexOf(item) === index),
'includes方法': (arr) => {
const result = [];
for (const item of arr) {
if (!result.includes(item)) result.push(item);
}
return result;
},
'Map方法': (arr) => {
const map = new Map();
const result = [];
for (const item of arr) {
if (!map.has(item)) {
map.set(item, true);
result.push(item);
}
}
return result;
},
'reduce方法': (arr) => arr.reduce((unique, item) => {
if (!unique.includes(item)) unique.push(item);
return unique;
}, [])
};
console.log('数组去重性能对比(数组长度:' + testData.length + ')');
console.log('='.repeat(50));
Object.entries(methods).forEach(([name, method]) => {
const testArray = [...testData]; // 创建副本
console.time(name);
const result = method(testArray);
console.timeEnd(name);
console.log(`${name} - 去重后长度: ${result.length}`);
console.log('-'.repeat(30));
});
}
// performanceComparison();
// 推荐使用顺序:
// 1. Set方法 - 最佳选择(简洁、高效、正确处理特殊值)
// 2. Map方法 - 次佳选择(高效、灵活)
// 3. includes方法 - 简单场景(代码清晰、正确处理NaN)
// 4. filter+indexOf - 不推荐(无法处理NaN)
// 5. reduce方法 - 不推荐(性能较差)数组扁平化是什么?这是将多维嵌套数组转换为一维数组的操作。数组扁平化在处理复杂数据结构时非常有用,是数据处理和算法实现的重要技能。
// 🎉 使用ES2019 flat()方法
const nestedArray = [1, [2, 3], [4, [5, 6]], 7];
// 扁平化一层
console.log('扁平化一层:', nestedArray.flat()); // [1, 2, 3, 4, [5, 6], 7]
// 扁平化两层
console.log('扁平化两层:', nestedArray.flat(2)); // [1, 2, 3, 4, 5, 6, 7]
// 完全扁平化(无限深度)
const deepNested = [1, [2, [3, [4, [5]]]]];
console.log('完全扁平化:', deepNested.flat(Infinity)); // [1, 2, 3, 4, 5]
// 实际应用:处理表格数据
const tableData = [
['Name', 'Age'],
[['Alice', 25], ['Bob', 30]],
[['Charlie', 35], ['David', 40]]
];
const flatTableData = tableData.flat(2);
console.log('表格数据扁平化:', flatTableData);
// ['Name', 'Age', 'Alice', 25, 'Bob', 30, 'Charlie', 35, 'David', 40]// 🎉 递归实现数组扁平化
function flattenRecursive(arr) {
const result = [];
for (const item of arr) {
if (Array.isArray(item)) {
result.push(...flattenRecursive(item)); // 递归处理嵌套数组
} else {
result.push(item);
}
}
return result;
}
// 带深度控制的递归版本
function flattenRecursiveWithDepth(arr, depth = 1) {
const result = [];
for (const item of arr) {
if (Array.isArray(item) && depth > 0) {
result.push(...flattenRecursiveWithDepth(item, depth - 1));
} else {
result.push(item);
}
}
return result;
}
// 测试递归扁平化
const testArray = [1, [2, 3], [4, [5, [6, 7]]], 8];
console.log('递归扁平化:', flattenRecursive(testArray));
console.log('递归扁平化(深度1):', flattenRecursiveWithDepth(testArray, 1));
console.log('递归扁平化(深度2):', flattenRecursiveWithDepth(testArray, 2));// 🎉 使用栈实现数组扁平化(避免递归)
function flattenWithStack(arr) {
const stack = [...arr];
const result = [];
while (stack.length > 0) {
const next = stack.pop();
if (Array.isArray(next)) {
stack.push(...next); // 将数组元素压入栈
} else {
result.push(next);
}
}
return result.reverse(); // 因为栈是后进先出,需要反转
}
// 保持顺序的栈实现
function flattenWithStackOrdered(arr) {
const stack = [...arr.map((item, index) => ({ item, index }))];
const result = [];
while (stack.length > 0) {
const { item, index } = stack.shift(); // 使用shift保持顺序
if (Array.isArray(item)) {
// 将数组元素插入到当前位置
const subItems = item.map((subItem, subIndex) => ({
item: subItem,
index: index + subIndex / 1000 // 保持相对顺序
}));
stack.unshift(...subItems);
} else {
result.push({ item, index });
}
}
return result.sort((a, b) => a.index - b.index).map(x => x.item);
}
// 简化的栈实现
function flattenIterative(arr) {
const result = [];
const stack = [...arr];
while (stack.length) {
const next = stack.pop();
if (Array.isArray(next)) {
stack.push(...next);
} else {
result.unshift(next); // 使用unshift保持顺序
}
}
return result;
}
// 测试栈实现
const stackTest = [1, [2, 3], [4, [5, 6]], 7];
console.log('栈实现扁平化:', flattenWithStack(stackTest));
console.log('迭代实现扁平化:', flattenIterative(stackTest));// 🎉 使用reduce实现数组扁平化
function flattenWithReduce(arr) {
return arr.reduce((flat, item) => {
return flat.concat(Array.isArray(item) ? flattenWithReduce(item) : item);
}, []);
}
// 使用reduce + 扩展运算符
function flattenWithReduceSpread(arr) {
return arr.reduce((flat, item) => {
return [...flat, ...(Array.isArray(item) ? flattenWithReduceSpread(item) : [item])];
}, []);
}
// 带深度控制的reduce版本
function flattenWithReduceDepth(arr, depth = Infinity) {
return depth > 0 ? arr.reduce((flat, item) => {
return flat.concat(
Array.isArray(item)
? flattenWithReduceDepth(item, depth - 1)
: item
);
}, []) : arr.slice();
}
// 测试reduce实现
const reduceTest = [1, [2, [3, [4]]], 5];
console.log('reduce扁平化:', flattenWithReduce(reduceTest));
console.log('reduce扁平化(深度2):', flattenWithReduceDepth(reduceTest, 2));// 🔴 数组扁平化性能对比
function flattenPerformanceTest() {
// 创建深度嵌套的测试数据
function createNestedArray(depth, width) {
if (depth === 0) return Math.floor(Math.random() * 100);
const arr = [];
for (let i = 0; i < width; i++) {
arr.push(createNestedArray(depth - 1, width));
}
return arr;
}
const testData = createNestedArray(4, 3); // 深度4,每层3个元素
const methods = {
'ES2019 flat()': (arr) => arr.flat(Infinity),
'递归实现': flattenRecursive,
'栈实现': flattenIterative,
'reduce实现': flattenWithReduce
};
console.log('数组扁平化性能对比');
console.log('='.repeat(40));
Object.entries(methods).forEach(([name, method]) => {
const testArray = JSON.parse(JSON.stringify(testData)); // 深拷贝
console.time(name);
const result = method(testArray);
console.timeEnd(name);
console.log(`${name} - 结果长度: ${result.length}`);
console.log('-'.repeat(25));
});
}
// flattenPerformanceTest();
// 推荐使用顺序:
// 1. ES2019 flat() - 最佳选择(原生实现,性能最好)
// 2. 递归实现 - 次佳选择(代码清晰,易于理解)
// 3. 栈实现 - 特殊场景(避免递归栈溢出)
// 4. reduce实现 - 函数式编程风格**多维数组是什么?**这是数组的元素本身也是数组的数据结构。多维数组处理在矩阵运算、表格数据处理、游戏开发等场景中非常重要。
// 🎉 二维数组的创建和操作
// 创建二维数组的方法
function create2DArray(rows, cols, defaultValue = 0) {
return Array.from({ length: rows }, () =>
Array.from({ length: cols }, () => defaultValue)
);
}
// 错误的创建方式(会共享引用)
function create2DArrayWrong(rows, cols, defaultValue = 0) {
return new Array(rows).fill(new Array(cols).fill(defaultValue)); // ❌ 共享引用
}
// 正确的创建方式
const matrix = create2DArray(3, 4, 0);
console.log('3x4矩阵:', matrix);
// 测试引用问题
const wrongMatrix = create2DArrayWrong(3, 3, 0);
wrongMatrix[0][0] = 1;
console.log('错误创建的矩阵:', wrongMatrix); // 所有行的第一个元素都变成1
const correctMatrix = create2DArray(3, 3, 0);
correctMatrix[0][0] = 1;
console.log('正确创建的矩阵:', correctMatrix); // 只有第一行第一个元素是1
// 二维数组的遍历
function traverse2DArray(matrix) {
console.log('二维数组遍历:');
// 方法1:传统for循环
for (let i = 0; i < matrix.length; i++) {
for (let j = 0; j < matrix[i].length; j++) {
console.log(`[${i}][${j}] = ${matrix[i][j]}`);
}
}
// 方法2:forEach
matrix.forEach((row, i) => {
row.forEach((cell, j) => {
console.log(`[${i}][${j}] = ${cell}`);
});
});
// 方法3:for...of
for (const [i, row] of matrix.entries()) {
for (const [j, cell] of row.entries()) {
console.log(`[${i}][${j}] = ${cell}`);
}
}
}
// 矩阵运算示例
class Matrix {
constructor(data) {
this.data = data;
this.rows = data.length;
this.cols = data[0].length;
}
// 矩阵转置
transpose() {
const result = create2DArray(this.cols, this.rows);
for (let i = 0; i < this.rows; i++) {
for (let j = 0; j < this.cols; j++) {
result[j][i] = this.data[i][j];
}
}
return new Matrix(result);
}
// 矩阵加法
add(other) {
if (this.rows !== other.rows || this.cols !== other.cols) {
throw new Error('矩阵维度不匹配');
}
const result = create2DArray(this.rows, this.cols);
for (let i = 0; i < this.rows; i++) {
for (let j = 0; j < this.cols; j++) {
result[i][j] = this.data[i][j] + other.data[i][j];
}
}
return new Matrix(result);
}
// 打印矩阵
print() {
console.table(this.data);
}
}
// 使用矩阵类
const matrixA = new Matrix([[1, 2], [3, 4]]);
const matrixB = new Matrix([[5, 6], [7, 8]]);
console.log('矩阵A:');
matrixA.print();
console.log('矩阵A转置:');
matrixA.transpose().print();
console.log('矩阵A + 矩阵B:');
matrixA.add(matrixB).print();// 🎉 三维数组和高维数组处理
// 创建三维数组
function create3DArray(depth, rows, cols, defaultValue = 0) {
return Array.from({ length: depth }, () =>
Array.from({ length: rows }, () =>
Array.from({ length: cols }, () => defaultValue)
)
);
}
// 创建任意维度数组
function createNDArray(dimensions, defaultValue = 0) {
if (dimensions.length === 0) return defaultValue;
if (dimensions.length === 1) return new Array(dimensions[0]).fill(defaultValue);
const [firstDim, ...restDims] = dimensions;
return Array.from({ length: firstDim }, () =>
createNDArray(restDims, defaultValue)
);
}
// 测试高维数组
const cube = create3DArray(2, 3, 4, 1); // 2x3x4的三维数组
console.log('三维数组:', cube);
const fourD = createNDArray([2, 2, 2, 2], 'x'); // 四维数组
console.log('四维数组:', fourD);
// 高维数组的扁平化
function flattenNDArray(arr, targetDimension = 1) {
let result = arr;
let currentDimension = getDimension(arr);
while (currentDimension > targetDimension) {
result = result.flat();
currentDimension--;
}
return result;
}
function getDimension(arr) {
if (!Array.isArray(arr)) return 0;
if (arr.length === 0) return 1;
return 1 + getDimension(arr[0]);
}
// 测试维度计算和扁平化
console.log('三维数组维度:', getDimension(cube));
console.log('扁平化为二维:', flattenNDArray(cube, 2));
console.log('完全扁平化:', flattenNDArray(cube, 1));// 🎉 实际应用:表格数据处理
class TableProcessor {
constructor(data) {
this.data = data;
}
// 获取列数据
getColumn(columnIndex) {
return this.data.map(row => row[columnIndex]);
}
// 获取行数据
getRow(rowIndex) {
return this.data[rowIndex];
}
// 转置表格
transpose() {
if (this.data.length === 0) return [];
const cols = this.data[0].length;
const result = [];
for (let j = 0; j < cols; j++) {
result.push(this.getColumn(j));
}
return new TableProcessor(result);
}
// 过滤行
filterRows(predicate) {
return new TableProcessor(this.data.filter(predicate));
}
// 排序
sortBy(columnIndex, ascending = true) {
const sorted = [...this.data].sort((a, b) => {
const aVal = a[columnIndex];
const bVal = b[columnIndex];
if (aVal < bVal) return ascending ? -1 : 1;
if (aVal > bVal) return ascending ? 1 : -1;
return 0;
});
return new TableProcessor(sorted);
}
// 添加计算列
addCalculatedColumn(calculator) {
const newData = this.data.map(row => [...row, calculator(row)]);
return new TableProcessor(newData);
}
// 分组统计
groupBy(columnIndex) {
const groups = {};
this.data.forEach(row => {
const key = row[columnIndex];
if (!groups[key]) {
groups[key] = [];
}
groups[key].push(row);
});
return groups;
}
// 打印表格
print() {
console.table(this.data);
}
}
// 使用表格处理器
const salesData = [
['Product', 'Category', 'Price', 'Quantity'],
['Laptop', 'Electronics', 999, 10],
['Mouse', 'Electronics', 25, 50],
['Desk', 'Furniture', 299, 5],
['Chair', 'Furniture', 199, 8]
];
const processor = new TableProcessor(salesData);
console.log('原始数据:');
processor.print();
console.log('按价格排序:');
processor.sortBy(2, false).print(); // 按价格降序
console.log('只显示电子产品:');
processor.filterRows(row => row[1] === 'Electronics').print();
console.log('添加总价列:');
processor.addCalculatedColumn(row =>
typeof row[2] === 'number' && typeof row[3] === 'number'
? row[2] * row[3]
: 'Total'
).print();
console.log('按类别分组:');
console.log(processor.groupBy(1));通过本节JavaScript数组高级操作的学习,你已经掌握:
"掌握数组的高级操作技巧是JavaScript进阶的重要标志,为处理复杂数据结构和算法实现打下坚实基础!"