Search K
Appearance
Appearance
📊 SEO元描述:2024年最新JavaScript数组方法教程,详解push、pop、splice、slice、concat等方法分类。包含改变原数组和不改变原数组方法对比,适合前端开发者掌握JavaScript数组操作技巧。
核心关键词:JavaScript数组方法2024、数组方法分类、splice和slice区别、JavaScript数组操作、改变原数组方法
长尾关键词:JavaScript数组方法有哪些、splice和slice怎么区分、JavaScript数组方法分类、数组方法改变原数组吗
通过本节JavaScript数组方法分类详解,你将系统性掌握:
改变原数组的方法是什么?这些是会直接修改原数组内容、长度或顺序的方法。改变原数组的方法会在原数组上进行操作,不会创建新数组,这在内存效率和性能方面有重要意义。
💡 学习建议:使用改变原数组的方法时要特别注意副作用,确保这是你想要的行为
数组两端操作方法提供了在数组开头和结尾进行增删操作的功能:
// 🎉 数组两端操作方法详解
const fruits = ['banana', 'orange'];
console.log('初始数组:', fruits); // ['banana', 'orange']
// 1. push() - 在数组末尾添加一个或多个元素
const pushResult = fruits.push('apple');
console.log('push后:', fruits); // ['banana', 'orange', 'apple']
console.log('push返回值:', pushResult); // 3 (新的数组长度)
// push可以添加多个元素
fruits.push('grape', 'kiwi');
console.log('push多个元素:', fruits); // ['banana', 'orange', 'apple', 'grape', 'kiwi']
// 2. pop() - 删除并返回数组最后一个元素
const popResult = fruits.pop();
console.log('pop后:', fruits); // ['banana', 'orange', 'apple', 'grape']
console.log('pop返回值:', popResult); // 'kiwi'
// 3. unshift() - 在数组开头添加一个或多个元素
const unshiftResult = fruits.unshift('mango');
console.log('unshift后:', fruits); // ['mango', 'banana', 'orange', 'apple', 'grape']
console.log('unshift返回值:', unshiftResult); // 5 (新的数组长度)
// unshift可以添加多个元素
fruits.unshift('pear', 'peach');
console.log('unshift多个元素:', fruits); // ['pear', 'peach', 'mango', 'banana', 'orange', 'apple', 'grape']
// 4. shift() - 删除并返回数组第一个元素
const shiftResult = fruits.shift();
console.log('shift后:', fruits); // ['peach', 'mango', 'banana', 'orange', 'apple', 'grape']
console.log('shift返回值:', shiftResult); // 'pear'// 🔴 数组两端操作的性能分析
// push和pop操作 - O(1)时间复杂度
const testArray1 = [];
console.time('push操作');
for (let i = 0; i < 100000; i++) {
testArray1.push(i);
}
console.timeEnd('push操作');
console.time('pop操作');
for (let i = 0; i < 100000; i++) {
testArray1.pop();
}
console.timeEnd('pop操作');
// unshift和shift操作 - O(n)时间复杂度(需要移动所有元素)
const testArray2 = [];
console.time('unshift操作');
for (let i = 0; i < 10000; i++) { // 注意:减少了测试数量
testArray2.unshift(i);
}
console.timeEnd('unshift操作');
console.time('shift操作');
for (let i = 0; i < 10000; i++) {
testArray2.shift();
}
console.timeEnd('shift操作');
// 实际应用示例
class Stack {
constructor() {
this.items = [];
}
push(item) {
return this.items.push(item);
}
pop() {
return this.items.pop();
}
peek() {
return this.items[this.items.length - 1];
}
isEmpty() {
return this.items.length === 0;
}
}
class Queue {
constructor() {
this.items = [];
}
enqueue(item) {
return this.items.push(item);
}
dequeue() {
return this.items.shift();
}
front() {
return this.items[0];
}
isEmpty() {
return this.items.length === 0;
}
}// 🎉 数组排序和反转方法
const numbers = [3, 1, 4, 1, 5, 9, 2, 6];
const fruits = ['banana', 'apple', 'orange', 'grape'];
// 1. reverse() - 反转数组元素顺序
console.log('原数组:', numbers); // [3, 1, 4, 1, 5, 9, 2, 6]
const reverseResult = numbers.reverse();
console.log('reverse后:', numbers); // [6, 2, 9, 5, 1, 4, 1, 3]
console.log('reverse返回值:', reverseResult); // [6, 2, 9, 5, 1, 4, 1, 3] (返回原数组引用)
// 2. sort() - 排序数组元素
console.log('原数组:', fruits); // ['banana', 'apple', 'orange', 'grape']
const sortResult = fruits.sort();
console.log('sort后:', fruits); // ['apple', 'banana', 'grape', 'orange']
console.log('sort返回值:', sortResult); // ['apple', 'banana', 'grape', 'orange'] (返回原数组引用)
// 🔴 sort()的默认行为 - 字符串排序
const nums = [10, 2, 1, 20, 3];
nums.sort();
console.log('数字默认排序:', nums); // [1, 10, 2, 20, 3] ❌ 不是数字排序!
// 正确的数字排序
const numbers2 = [10, 2, 1, 20, 3];
numbers2.sort((a, b) => a - b); // 升序
console.log('数字升序排序:', numbers2); // [1, 2, 3, 10, 20]
const numbers3 = [10, 2, 1, 20, 3];
numbers3.sort((a, b) => b - a); // 降序
console.log('数字降序排序:', numbers3); // [20, 10, 3, 2, 1]
// 复杂对象排序
const students = [
{ name: 'Alice', age: 23, grade: 85 },
{ name: 'Bob', age: 21, grade: 92 },
{ name: 'Charlie', age: 22, grade: 78 }
];
// 按年龄排序
students.sort((a, b) => a.age - b.age);
console.log('按年龄排序:', students);
// 按成绩排序
students.sort((a, b) => b.grade - a.grade);
console.log('按成绩排序:', students);
// 按姓名排序
students.sort((a, b) => a.name.localeCompare(b.name));
console.log('按姓名排序:', students);splice方法是JavaScript中最强大的数组操作方法,可以同时进行删除、插入和替换操作:
// 🎉 splice方法的强大功能详解
// 语法:array.splice(start, deleteCount, item1, item2, ...)
const originalArray = ['a', 'b', 'c', 'd', 'e', 'f'];
// 1. 只删除元素
const arr1 = [...originalArray];
const deleted1 = arr1.splice(2, 2); // 从索引2开始删除2个元素
console.log('删除操作:', arr1); // ['a', 'b', 'e', 'f']
console.log('被删除的元素:', deleted1); // ['c', 'd']
// 2. 只插入元素
const arr2 = [...originalArray];
const deleted2 = arr2.splice(2, 0, 'x', 'y'); // 在索引2插入'x', 'y'
console.log('插入操作:', arr2); // ['a', 'b', 'x', 'y', 'c', 'd', 'e', 'f']
console.log('被删除的元素:', deleted2); // [] (没有删除)
// 3. 替换元素
const arr3 = [...originalArray];
const deleted3 = arr3.splice(2, 2, 'x', 'y', 'z'); // 删除2个,插入3个
console.log('替换操作:', arr3); // ['a', 'b', 'x', 'y', 'z', 'e', 'f']
console.log('被删除的元素:', deleted3); // ['c', 'd']
// 4. 负数索引
const arr4 = [...originalArray];
const deleted4 = arr4.splice(-2, 1, 'x'); // 从倒数第2个位置删除1个,插入'x'
console.log('负数索引:', arr4); // ['a', 'b', 'c', 'd', 'x', 'f']
console.log('被删除的元素:', deleted4); // ['e']
// 5. 删除到末尾
const arr5 = [...originalArray];
const deleted5 = arr5.splice(3); // 从索引3开始删除到末尾
console.log('删除到末尾:', arr5); // ['a', 'b', 'c']
console.log('被删除的元素:', deleted5); // ['d', 'e', 'f']// 🎉 splice方法的实际应用
// 场景1:数组元素的增删改查
class ArrayManager {
constructor(initialArray = []) {
this.data = [...initialArray];
}
// 在指定位置插入元素
insert(index, ...items) {
this.data.splice(index, 0, ...items);
return this;
}
// 删除指定位置的元素
remove(index, count = 1) {
return this.data.splice(index, count);
}
// 替换指定位置的元素
replace(index, count, ...newItems) {
return this.data.splice(index, count, ...newItems);
}
// 移动元素位置
move(fromIndex, toIndex) {
const [item] = this.data.splice(fromIndex, 1);
this.data.splice(toIndex, 0, item);
return this;
}
// 获取数组副本
toArray() {
return [...this.data];
}
}
// 使用示例
const manager = new ArrayManager(['a', 'b', 'c', 'd']);
console.log('初始:', manager.toArray()); // ['a', 'b', 'c', 'd']
manager.insert(2, 'x', 'y');
console.log('插入后:', manager.toArray()); // ['a', 'b', 'x', 'y', 'c', 'd']
manager.remove(1, 2);
console.log('删除后:', manager.toArray()); // ['a', 'y', 'c', 'd']
manager.replace(1, 1, 'z');
console.log('替换后:', manager.toArray()); // ['a', 'z', 'c', 'd']
manager.move(0, 2);
console.log('移动后:', manager.toArray()); // ['z', 'c', 'a', 'd']
// 场景2:数组去重(保持顺序)
function removeDuplicates(arr) {
for (let i = 0; i < arr.length; i++) {
for (let j = i + 1; j < arr.length; j++) {
if (arr[i] === arr[j]) {
arr.splice(j, 1);
j--; // 调整索引
}
}
}
return arr;
}
const duplicateArray = [1, 2, 2, 3, 3, 3, 4];
removeDuplicates(duplicateArray);
console.log('去重后:', duplicateArray); // [1, 2, 3, 4]不改变原数组的方法是什么?这些是不会修改原数组,而是返回新数组或其他值的方法。不改变原数组的方法遵循函数式编程的原则,避免副作用,提高代码的可预测性。
slice vs splice对比是JavaScript中最容易混淆的概念之一:
// 🔴 slice vs splice 详细对比
const originalArray = ['a', 'b', 'c', 'd', 'e'];
// === slice方法 ===
console.log('=== slice方法测试 ===');
const arr1 = [...originalArray];
const sliceResult = arr1.slice(1, 4); // 从索引1到4(不包括4)
console.log('原数组:', arr1); // ['a', 'b', 'c', 'd', 'e'] ✅ 未改变
console.log('slice结果:', sliceResult); // ['b', 'c', 'd'] ✅ 新数组
console.log('slice返回值类型:', typeof sliceResult); // object (数组)
// === splice方法 ===
console.log('=== splice方法测试 ===');
const arr2 = [...originalArray];
const spliceResult = arr2.splice(1, 3, 'x', 'y'); // 从索引1删除3个,插入'x', 'y'
console.log('原数组:', arr2); // ['a', 'x', 'y', 'e'] ❌ 已改变
console.log('splice结果:', spliceResult); // ['b', 'c', 'd'] ✅ 被删除的元素
console.log('splice返回值类型:', typeof spliceResult); // object (数组)
// === 对比总结 ===
const comparisonTable = {
'特性': ['slice', 'splice'],
'是否改变原数组': ['否', '是'],
'返回值': ['新数组(提取的元素)', '数组(被删除的元素)'],
'主要用途': ['提取子数组', '增删改数组元素'],
'参数': ['(start, end)', '(start, deleteCount, ...items)'],
'性能': ['创建新数组,内存开销大', '直接修改,内存开销小']
};
console.table(comparisonTable);// 🎉 slice和splice的实际应用场景
// 场景1:数组分页 - 使用slice
function paginate(array, pageSize, pageNumber) {
const start = (pageNumber - 1) * pageSize;
const end = start + pageSize;
return array.slice(start, end); // 不改变原数组
}
const data = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
console.log('第1页:', paginate(data, 3, 1)); // [1, 2, 3]
console.log('第2页:', paginate(data, 3, 2)); // [4, 5, 6]
console.log('原数组:', data); // [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] 未改变
// 场景2:数组元素管理 - 使用splice
class TodoList {
constructor() {
this.todos = [];
}
add(todo) {
this.todos.push(todo);
}
remove(index) {
return this.todos.splice(index, 1)[0]; // 改变原数组
}
update(index, newTodo) {
const [oldTodo] = this.todos.splice(index, 1, newTodo);
return oldTodo;
}
getAll() {
return this.todos.slice(); // 返回副本,不暴露内部数组
}
}
const todoList = new TodoList();
todoList.add('学习JavaScript');
todoList.add('写代码');
todoList.add('休息');
console.log('所有任务:', todoList.getAll());
todoList.remove(1);
console.log('删除后:', todoList.getAll());
// 场景3:函数式编程 - 优先使用slice
function getFirstN(array, n) {
return array.slice(0, n); // 函数式,无副作用
}
function getLastN(array, n) {
return array.slice(-n); // 函数式,无副作用
}
const numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
console.log('前3个:', getFirstN(numbers, 3)); // [1, 2, 3]
console.log('后3个:', getLastN(numbers, 3)); // [8, 9, 10]
console.log('原数组:', numbers); // 保持不变// 🎉 concat和join方法详解
// 1. concat() - 连接数组
const arr1 = [1, 2, 3];
const arr2 = [4, 5, 6];
const arr3 = [7, 8, 9];
// 连接多个数组
const concatenated = arr1.concat(arr2, arr3);
console.log('concat结果:', concatenated); // [1, 2, 3, 4, 5, 6, 7, 8, 9]
console.log('原数组arr1:', arr1); // [1, 2, 3] 未改变
// 连接数组和单个元素
const mixed = arr1.concat(4, [5, 6], 7);
console.log('混合连接:', mixed); // [1, 2, 3, 4, 5, 6, 7]
// 现代替代方案:扩展运算符
const modernConcat = [...arr1, ...arr2, ...arr3];
console.log('扩展运算符:', modernConcat); // [1, 2, 3, 4, 5, 6, 7, 8, 9]
// 2. join() - 数组转字符串
const fruits = ['apple', 'banana', 'orange'];
// 默认分隔符(逗号)
console.log('默认join:', fruits.join()); // 'apple,banana,orange'
// 自定义分隔符
console.log('空格分隔:', fruits.join(' ')); // 'apple banana orange'
console.log('横线分隔:', fruits.join(' - ')); // 'apple - banana - orange'
console.log('无分隔符:', fruits.join('')); // 'applebananaorange'
// 实际应用:生成URL路径
const pathSegments = ['api', 'users', '123', 'profile'];
const url = '/' + pathSegments.join('/');
console.log('URL路径:', url); // '/api/users/123/profile'
// 实际应用:生成SQL查询
const columns = ['id', 'name', 'email', 'created_at'];
const sql = `SELECT ${columns.join(', ')} FROM users`;
console.log('SQL查询:', sql); // 'SELECT id, name, email, created_at FROM users'// 🎉 数组查找方法详解
const numbers = [1, 2, 3, 2, 4, 2, 5];
const fruits = ['apple', 'banana', 'orange', 'banana'];
// 1. indexOf() - 查找元素第一次出现的索引
console.log('indexOf(2):', numbers.indexOf(2)); // 1 (第一次出现)
console.log('indexOf(6):', numbers.indexOf(6)); // -1 (不存在)
console.log('indexOf(2, 3):', numbers.indexOf(2, 3)); // 3 (从索引3开始查找)
// 2. lastIndexOf() - 查找元素最后一次出现的索引
console.log('lastIndexOf(2):', numbers.lastIndexOf(2)); // 5 (最后一次出现)
console.log('lastIndexOf(6):', numbers.lastIndexOf(6)); // -1 (不存在)
console.log('lastIndexOf(2, 4):', numbers.lastIndexOf(2, 4)); // 3 (从索引4向前查找)
// 3. includes() - 检查数组是否包含某个元素 (ES2016)
console.log('includes(2):', numbers.includes(2)); // true
console.log('includes(6):', numbers.includes(6)); // false
console.log('includes(2, 3):', numbers.includes(2, 3)); // true (从索引3开始查找)
// 🔴 特殊值的查找
const specialValues = [1, NaN, null, undefined, 0, false, ''];
// NaN的特殊处理
console.log('indexOf(NaN):', specialValues.indexOf(NaN)); // -1 (indexOf无法找到NaN)
console.log('includes(NaN):', specialValues.includes(NaN)); // true (includes可以找到NaN)
// null和undefined
console.log('indexOf(null):', specialValues.indexOf(null)); // 2
console.log('indexOf(undefined):', specialValues.indexOf(undefined)); // 3
console.log('includes(null):', specialValues.includes(null)); // true
console.log('includes(undefined):', specialValues.includes(undefined)); // true
// 实际应用:数组去重
function removeDuplicatesWithIndexOf(arr) {
const result = [];
for (let i = 0; i < arr.length; i++) {
if (result.indexOf(arr[i]) === -1) {
result.push(arr[i]);
}
}
return result;
}
function removeDuplicatesWithIncludes(arr) {
const result = [];
for (const item of arr) {
if (!result.includes(item)) {
result.push(item);
}
}
return result;
}
const duplicates = [1, 2, 2, 3, 3, 3, 4, NaN, NaN];
console.log('indexOf去重:', removeDuplicatesWithIndexOf(duplicates));
console.log('includes去重:', removeDuplicatesWithIncludes(duplicates));
// 实际应用:权限检查
function hasPermission(userPermissions, requiredPermission) {
return userPermissions.includes(requiredPermission);
}
const userPerms = ['read', 'write', 'delete'];
console.log('有写权限:', hasPermission(userPerms, 'write')); // true
console.log('有管理权限:', hasPermission(userPerms, 'admin')); // false通过本节JavaScript数组方法分类详解的学习,你已经掌握:
"掌握数组方法的分类和特点是JavaScript编程的重要技能,为后续学习高阶函数和函数式编程打下基础!"