JavaScript:10个数组方法/属性
1. length
(属性)
深度解析:
技术原理:动态反映数组当前元素数量,基于最大索引值+1
特殊行为:
设置小于当前长度:截断数组(不可逆操作)
设置大于当前长度:创建空位(empty slots),访问返回
undefined
但迭代跳过空位与
undefined
的区别:[,1]
vs[undefined,1]
使用场景:
1.快速清空数组(性能最优):
const data = [/* 大量数据 */];
data.length = 0; // 比 data = [] 更高效
2.数组截断:
const logs = ['log1', 'log2', 'log3', 'log4'];
// 只保留最后2条日志
logs.length = Math.min(logs.length, 2);
3.预分配大数组(谨慎使用):
const pixelData = new Array(1920*1080); // 创建200万空位
// 后续填充数据(比动态push高效)
注意事项:
// 空位陷阱示例
const sparseArr = [1, , 3];
console.log(sparseArr.length); // 3
console.log(sparseArr[1]); // undefined// forEach跳过空位
sparseArr.forEach(v => console.log(v)); // 只输出1和3// 解决:显式填充undefined
const denseArr = Array.from(sparseArr); // [1, undefined, 3]
2. push()
深度解析:
技术原理:修改原数组,在末尾添加元素,返回新长度
性能特点:O(1)时间复杂度(摊销常数时间)
使用场景:
1.动态数据收集:
const userInputs = [];
inputElement.addEventListener('change', (e) => {userInputs.push(e.target.value);
});
2.栈操作(LIFO):
const historyStack = [];
function doAction(action) {historyStack.push(action);// 执行操作...
}
3.批量添加元素:
// 优于多次调用push
const newItems = ['item4', 'item5', 'item6'];
items.push(...newItems); // 扩展运算符
最佳实践:
// 避免在循环中连续push
// 反例(性能差):
for(let i=0; i<10000; i++) {arr.push(i);
}// 正例(预分配):
const arr = new Array(10000);
for(let i=0; i<10000; i++) {arr[i] = i;
}
3. pop()
深度解析:
技术原理:移除最后一个元素并返回,修改原数组长度
边界情况:空数组调用返回
undefined
使用场景:
1.栈操作(LIFO):
function undo() {if(historyStack.length > 0) {const lastAction = historyStack.pop();revertAction(lastAction);}
}
2.处理任务队列:
while(taskQueue.length > 0) {const task = taskQueue.pop();executeTask(task);
}
3.递归处理嵌套结构:
function flatten(arr) {const result = [];while(arr.length) {const next = arr.pop();if(Array.isArray(next)) {arr.push(...next);} else {result.push(next);}}return result.reverse();
}
注意事项:
// 不可逆操作警告
const original = [1, 2, 3];
const last = original.pop();
console.log(original); // [1,2] - 永久改变
4. shift()
深度解析:
技术原理:移除首元素并返回,所有后续元素前移
性能问题:O(n)时间复杂度,大数据量慎用
使用场景:
1.队列处理(FIFO):
const messageQueue = [];// 入队
socket.on('message', msg => messageQueue.push(msg));// 处理队列
setInterval(() => {if(messageQueue.length > 0) {processMessage(messageQueue.shift());}
}, 100);
2.流式数据处理:
while(dataStream.length) {const packet = dataStream.shift();parsePacket(packet);
}
性能优化:
// 替代方案:使用索引指针
class Queue {constructor() {this.items = {};this.front = 0;this.rear = 0;}enqueue(item) {this.items[this.rear++] = item;}dequeue() {if(this.front >= this.rear) return null;const item = this.items[this.front];delete this.items[this.front++];return item;}
}
5. unshift()
深度解析:
技术原理:在数组开头添加元素,所有现有元素后移
性能问题:O(n)时间复杂度,大数据量避免使用
使用场景:
1.优先级队列:
const tasks = [];function addTask(task, isHighPriority) {if(isHighPriority) {tasks.unshift(task); // 高优先级插队} else {tasks.push(task);}
}
2.时间线展示(最新在前):
const timeline = [];function addEvent(event) {timeline.unshift(event); // 新事件在开头if(timeline.length > 100) timeline.pop(); // 限制长度
}
替代方案:
// 使用reverse + push 替代
const arr = [3,4];
arr.reverse().push(1,2);
arr.reverse(); // [1,2,3,4]// 大数据量使用链表
class LinkedList {// 实现链表结构...
}
6. forEach()
深度解析:
技术原理:为每个元素执行回调(元素,索引,原数组)
重要特性:
无法用
break
中断空位会被跳过
不等待异步操作
使用场景:
1.DOM批量操作:
const buttons = document.querySelectorAll('button');
buttons.forEach(btn => {btn.addEventListener('click', handleClick);
});
2.执行副作用操作:
const users = [/*...*/];
users.forEach(user => {saveToLocalStorage(user.id, user);
});
异步处理:
// 错误:不会等待
items.forEach(async item => {await processItem(item); // 不会顺序执行
});// 正确:使用for...of
async function processAll() {for(const item of items) {await processItem(item);}
}
7. map()
深度解析:
技术原理:创建新数组,每个元素是回调返回值
核心特性:
不修改原数组(纯函数)
保持数组长度不变
跳过空位
使用场景:
1.数据格式转换:
const apiResponse = [{ id: 1, name: 'Alice' },{ id: 2, name: 'Bob' }
];const userIds = apiResponse.map(user => user.id); // [1,2]
2.JSX列表渲染:
function UserList({ users }) {return (<ul>{users.map(user => (<li key={user.id}>{user.name}</li>))}</ul>);
}
3.数学计算:
const temperaturesC = [0, 25, 100];
const temperaturesF = temperaturesC.map(c => c * 9/5 + 32);
最佳实践:
// 避免在map中产生副作用
// 反例:
items.map(item => {saveItem(item); // 副作用操作return item.id;
});// 正例:使用forEach处理副作用
const ids = [];
items.forEach(item => {saveItem(item);ids.push(item.id);
});
8. filter()
深度解析:
技术原理:返回回调返回truthy的元素组成的新数组
重要特性:
不修改原数组
结果数组长度 <= 原数组
跳过空位
使用场景:
1.数据筛选:
const products = [/*...*/];
const availableProducts = products.filter(p => p.stock > 0);
2.搜索功能:
function search(query) {return items.filter(item => item.name.toLowerCase().includes(query.toLowerCase()));
}
3.数据清理:
const userInput = ['', 'valid', null, 'data'];
const validInput = userInput.filter(Boolean); // ['valid','data']
高级用法:
// 链式调用
const result = data.filter(item => item.category === 'electronics').filter(item => item.price < 100).map(item => item.name);// 结合索引去重
const unique = array.filter((item, index) => array.indexOf(item) === index
);
9. find()
深度解析:
技术原理:返回第一个使回调返回truthy的元素
重要特性:
找到即停止遍历
未找到返回
undefined
比
filter()[0]
更高效
使用场景:
1.ID查找:
const users = [/*...*/];
function findUser(id) {return users.find(user => user.id === id);
}
2.条件查找:
const inventory = [{ name: 'apple', color: 'red' },{ name: 'banana', color: 'yellow' }
];const yellowFruit = inventory.find(f => f.color === 'yellow');
3.配置查找:
const configOptions = [{ env: 'dev', apiUrl: 'dev.api.com' },{ env: 'prod', apiUrl: 'api.com' }
];const currentConfig = configOptions.find(c => c.env === process.env.NODE_ENV
);
与findIndex
配合:
const index = users.findIndex(user => user.id === 123);
if(index !== -1) {// 更新用户users[index] = updatedUser;
}
10. includes()
深度解析:
技术原理:使用SameValueZero算法检查包含性
关键特性:
NaN
可以匹配NaN
区分+0和-0
对象比较引用而非内容
使用场景:
1.简单值存在检查:
const validStatuses = ['active', 'pending', 'completed'];function isValidStatus(status) {return validStatuses.includes(status);
}
2.功能开关控制:
const enabledFeatures = getUserFeatures();if(enabledFeatures.includes('dark_mode')) {enableDarkMode();
}
3.白名单验证:
const ALLOWED_FILE_TYPES = ['image/jpeg', 'image/png'];function isValidFile(file) {return ALLOWED_FILE_TYPES.includes(file.type);
}
对象数组处理:
// 无法直接查找对象
const items = [{id:1}, {id:2}];
console.log(items.includes({id:1})); // false// 解决方案:
const target = {id:1};
const itemSet = new Set(items.map(i => i.id));
console.log(itemSet.has(1)); // true// 或使用some
const exists = items.some(item => item.id === 1);
专业级总结:选择指南
场景 | 推荐方法 | 原因 |
---|---|---|
遍历数组 | for...of 或 forEach | 简洁性 vs 可中断性 |
数据转换 | map | 纯函数,无副作用 |
数据筛选 | filter | 声明式编程 |
查找元素 | find / findIndex | 高效(短路特性) |
存在检查 | includes (简单值) / some (复杂) | 语义化清晰 |
添加元素 | push (尾) / unshift (头,慎用) | 性能考虑 |
移除元素 | pop (尾) / shift (头,慎用) | 性能考虑 |
清空数组 | arr.length = 0 | 最高性能 |
异步遍历 | for...of + await | 顺序执行 |
复杂数据操作 | reduce (未列出) | 灵活处理累积操作 |
高级建议:
1.不可变性原则:优先使用map
、filter
、slice
等非变异方法
2.性能敏感操作:
// 大数组操作使用TypedArray
const buffer = new Float64Array(1000000);// 替代shift/unshift
class CircularBuffer {// 实现循环缓冲区
}
3.函数式编程组合:
import { pipe } from 'lodash/fp';const processData = pipe(filter(validCondition),map(transform),sort(comparator)
);const result = processData(rawData);