JavaScript系列(8)-- Array高级操作
JavaScript Array高级操作 📚
在前七篇文章中,我们探讨了JavaScript的语言特性、ECMAScript标准、引擎工作原理、数值类型、字符串处理、Symbol类型和Object高级特性。今天,让我们深入了解JavaScript中的Array高级操作。数组是最常用的数据结构之一,掌握其高级操作可以让我们更优雅地处理数据。
数组基础回顾 🌟
💡 小知识:JavaScript中的数组实际上是一种特殊的对象,它的索引是字符串类型的数字,并且有一个特殊的length属性。这种实现方式使得JavaScript数组比传统的数组更灵活,但在某些情况下性能可能不如传统数组。
数组的创建和初始化 📊
// 1. 数组创建的多种方式
function arrayCreation() {
// 字面量方式
const arr1 = [1, 2, 3, 4, 5];
// 构造函数方式
const arr2 = new Array(3); // 创建长度为3的空数组
const arr3 = new Array(1, 2, 3); // 创建包含1,2,3的数组
// Array.from方式
const arr4 = Array.from('hello'); // ['h', 'e', 'l', 'l', 'o']
const arr5 = Array.from({ length: 5 }, (_, i) => i + 1); // [1, 2, 3, 4, 5]
// Array.of方式
const arr6 = Array.of(3); // [3]
const arr7 = Array.of(1, 2, 3); // [1, 2, 3]
// 扩展运算符
const existing = [1, 2, 3];
const arr8 = [...existing, 4, 5]; // [1, 2, 3, 4, 5]
}
// 2. 类型化数组
function typedArrays() {
// 创建类型化数组
const int8Array = new Int8Array(4);
const uint8Array = new Uint8Array(4);
const int16Array = new Int16Array(4);
const float32Array = new Float32Array(4);
const float64Array = new Float64Array(4);
// 从普通数组创建
const numbers = [1, 2, 3, 4];
const typed = new Int32Array(numbers);
// 类型化数组的操作
typed[0] = 10;
console.log(typed.byteLength); // 字节长度
console.log(typed.buffer); // 底层ArrayBuffer
}
// 3. 数组缓冲区和视图
function arrayBuffers() {
// 创建ArrayBuffer
const buffer = new ArrayBuffer(16);
// 创建不同的视图
const int32View = new Int32Array(buffer);
const float64View = new Float64Array(buffer);
const uint8View = new Uint8Array(buffer);
// 通过视图操作数据
int32View[0] = 42;
console.log(uint8View[0]); // 查看字节级表示
}
数组操作方法 🔧
JavaScript提供了丰富的数组操作方法:
// 1. 基本操作
function basicOperations() {
const arr = [1, 2, 3, 4, 5];
// 添加和删除元素
arr.push(6); // 末尾添加
arr.unshift(0); // 开头添加
arr.pop(); // 末尾删除
arr.shift(); // 开头删除
// 切片和拼接
const slice = arr.slice(1, 3); // 复制部分数组
const spliced = arr.splice(1, 2, 'a', 'b'); // 替换元素
// 合并数组
const arr1 = [1, 2];
const arr2 = [3, 4];
const combined = arr1.concat(arr2);
// 或使用扩展运算符
const combined2 = [...arr1, ...arr2];
}
// 2. 高阶函数操作
function higherOrderOperations() {
const numbers = [1, 2, 3, 4, 5];
// map: 转换每个元素
const doubled = numbers.map(x => x * 2);
// filter: 筛选元素
const evens = numbers.filter(x => x % 2 === 0);
// reduce: 累积计算
const sum = numbers.reduce((acc, cur) => acc + cur, 0);
// find/findIndex: 查找元素
const found = numbers.find(x => x > 3);
const foundIndex = numbers.findIndex(x => x > 3);
// every/some: 条件检查
const allPositive = numbers.every(x => x > 0);
const hasEven = numbers.some(x => x % 2 === 0);
// flatMap: 映射并展平结果
const pairs = numbers.flatMap(x => [x, x * 2]);
}
// 3. 排序和搜索
function sortingAndSearching() {
const items = [
{ name: '苹果', price: 5 },
{ name: '香蕉', price: 3 },
{ name: '橙子', price: 4 }
];
// 基本排序
items.sort((a, b) => a.price - b.price);
// 自定义排序
items.sort((a, b) => {
if (a.name < b.name) return -1;
if (a.name > b.name) return 1;
return 0;
});
// 二分查找
const numbers = [1, 3, 5, 7, 9, 11];
const index = numbers.indexOf(7);
// 自定义二分查找
function binarySearch(arr, target) {
let left = 0;
let right = arr.length - 1;
while (left <= right) {
const mid = Math.floor((left + right) / 2);
if (arr[mid] === target) return mid;
if (arr[mid] < target) left = mid + 1;
else right = mid - 1;
}
return -1;
}
}
数组的高级技巧 🎯
让我们看看一些高级的数组操作技巧:
// 1. 数组去重
function arrayDeduplication() {
// 使用Set
function uniqueArray1(arr) {
return [...new Set(arr)];
}
// 使用filter
function uniqueArray2(arr) {
return arr.filter((item, index) => arr.indexOf(item) === index);
}
// 使用reduce
function uniqueArray3(arr) {
return arr.reduce((unique, item) =>
unique.includes(item) ? unique : [...unique, item],
[]);
}
// 对象数组去重
function uniqueObjectArray(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;
});
}
}
// 2. 数组分组和分块
function arrayGrouping() {
// 按条件分组
function groupBy(arr, key) {
return arr.reduce((groups, item) => {
const value = typeof key === 'function' ? key(item) : item[key];
(groups[value] = groups[value] || []).push(item);
return groups;
}, {});
}
// 分块
function chunk(arr, size) {
return Array.from(
{ length: Math.ceil(arr.length / size) },
(_, i) => arr.slice(i * size, (i + 1) * size)
);
}
// 按数量分割
function partition(arr, n) {
const size = Math.ceil(arr.length / n);
return chunk(arr, size);
}
}
// 3. 数组交集、并集和差集
function arraySetOperations() {
// 交集
function intersection(arr1, arr2) {
return arr1.filter(item => arr2.includes(item));
}
// 并集
function union(arr1, arr2) {
return [...new Set([...arr1, ...arr2])];
}
// 差集
function difference(arr1, arr2) {
return arr1.filter(item => !arr2.includes(item));
}
// 对称差集
function symmetricDifference(arr1, arr2) {
return arr1.filter(item => !arr2.includes(item))
.concat(arr2.filter(item => !arr1.includes(item)));
}
}
数组性能优化 ⚡
处理大型数组时的性能优化技巧:
// 1. 预分配内存
function memoryPreallocation() {
// 预分配数组大小
const n = 1000000;
const arr = new Array(n);
// 不好的做法
const dynamicArr = [];
for (let i = 0; i < n; i++) {
dynamicArr.push(i); // 可能导致多次重新分配内存
}
// 好的做法
const preallocatedArr = new Array(n);
for (let i = 0; i < n; i++) {
preallocatedArr[i] = i;
}
}
// 2. 批量操作优化
function batchOperations() {
// 使用TypedArray进行数值计算
function computeSum(arr) {
const typed = new Float64Array(arr);
let sum = 0;
for (let i = 0; i < typed.length; i++) {
sum += typed[i];
}
return sum;
}
// 批量插入优化
function batchInsert(arr, items) {
const temp = [...arr];
temp.push(...items);
return temp;
}
}
// 3. 迭代器优化
function iteratorOptimization() {
// 使用for...of代替forEach
function sumArray(arr) {
let sum = 0;
for (const num of arr) {
sum += num;
}
return sum;
}
// 使用迭代器处理大数据
function* chunks(arr, size) {
for (let i = 0; i < arr.length; i += size) {
yield arr.slice(i, i + size);
}
}
}
实际应用场景 💼
让我们看看数组在实际开发中的一些应用:
// 1. 数据处理
class DataProcessor {
// 数据转换
static transform(data, transformers) {
return data.map(item =>
transformers.reduce((acc, transformer) =>
transformer(acc), item
)
);
}
// 数据过滤和排序
static filterAndSort(data, filters, sorter) {
return data
.filter(item => filters.every(filter => filter(item)))
.sort(sorter);
}
// 数据聚合
static aggregate(data, groupBy, aggregator) {
const groups = this.groupBy(data, groupBy);
return Object.entries(groups).map(([key, group]) => ({
key,
value: aggregator(group)
}));
}
}
// 2. 虚拟列表
class VirtualList {
constructor(data, pageSize) {
this.data = data;
this.pageSize = pageSize;
this.currentPage = 0;
}
getCurrentPage() {
const start = this.currentPage * this.pageSize;
return this.data.slice(start, start + this.pageSize);
}
next() {
if (this.hasNext()) {
this.currentPage++;
return this.getCurrentPage();
}
return [];
}
previous() {
if (this.hasPrevious()) {
this.currentPage--;
return this.getCurrentPage();
}
return [];
}
hasNext() {
return (this.currentPage + 1) * this.pageSize < this.data.length;
}
hasPrevious() {
return this.currentPage > 0;
}
}
// 3. 数据缓存
class ArrayCache {
constructor(maxSize = 1000) {
this.maxSize = maxSize;
this.cache = new Map();
}
set(key, array) {
if (this.cache.size >= this.maxSize) {
const firstKey = this.cache.keys().next().value;
this.cache.delete(firstKey);
}
this.cache.set(key, array);
}
get(key) {
return this.cache.get(key);
}
has(key) {
return this.cache.has(key);
}
clear() {
this.cache.clear();
}
}
最佳实践建议 💡
- 数组操作最佳实践
// 1. 避免稀疏数组
function avoidSparseArrays() {
// 不好的做法
const sparse = [1, , 3];
// 好的做法
const dense = [1, null, 3];
// 转换稀疏数组为密集数组
const densified = sparse.filter(() => true);
}
// 2. 使用合适的数组方法
function chooseRightMethods() {
const arr = [1, 2, 3, 4, 5];
// 查找元素
// 不好的做法
const found1 = arr.filter(x => x === 3)[0];
// 好的做法
const found2 = arr.find(x => x === 3);
// 转换数组
// 不好的做法
const transformed1 = arr.reduce((acc, x) => [...acc, x * 2], []);
// 好的做法
const transformed2 = arr.map(x => x * 2);
}
// 3. 性能考虑
function performanceConsiderations() {
// 避免频繁修改数组长度
const arr = [];
const n = 1000;
// 不好的做法
for (let i = 0; i < n; i++) {
arr.push(i);
}
// 好的做法
const arr2 = Array.from({ length: n }, (_, i) => i);
}
- 错误处理和验证
// 1. 数组验证
function validateArray(arr) {
if (!Array.isArray(arr)) {
throw new TypeError('参数必须是数组');
}
if (arr.length === 0) {
throw new Error('数组不能为空');
}
return true;
}
// 2. 安全的数组操作
function safeArrayOperations() {
function safeGet(arr, index, defaultValue = null) {
if (!Array.isArray(arr)) return defaultValue;
if (index < 0 || index >= arr.length) return defaultValue;
return arr[index];
}
function safeSplice(arr, start, deleteCount, ...items) {
const copy = [...arr];
copy.splice(start, deleteCount, ...items);
return copy;
}
}
// 3. 类型检查
function arrayTypeChecking() {
function isNumberArray(arr) {
return Array.isArray(arr) && arr.every(x => typeof x === 'number');
}
function isObjectArray(arr) {
return Array.isArray(arr) && arr.every(x => x && typeof x === 'object');
}
}
结语 📝
JavaScript的数组操作非常强大和灵活,掌握这些高级操作可以帮助我们更好地处理数据。我们学习了:
- 数组的创建和初始化方法
- 常用的数组操作方法
- 高级数组操作技巧
- 性能优化和最佳实践
- 实际应用场景
💡 学习建议:在处理数组时,要根据具体场景选择合适的方法,注意性能影响,特别是在处理大型数组时。同时,要注意数组操作的副作用,优先使用不改变原数组的方法。
如果你觉得这篇文章有帮助,欢迎点赞收藏,也期待在评论区看到你的想法和建议!👇
终身学习,共同成长。
咱们下一期见
💻