JavaScript篇:这些数组方法会悄悄改变你的原数组 - 前端工程师必备知识

283 阅读4分钟

🎓 作者简介前端领域优质创作者

🚪 资源导航: 传送门=>

🎬 个人主页:  江城开朗的豌豆

🌐 个人网站:    江城开朗的豌豆 🌍

📧 个人邮箱: YANG_TAO_WEB@163.com 📩

💬 个人微信:     y_t_t_t_ 📱

📌  座  右 铭: 生活就像心电图,一帆风顺就证明你挂了 💔

👥 QQ群:  906392632 (前端技术交流群) 💬

 作为前端开发者最近在代码审查时发现了一个隐蔽的Bug:同事在无意中修改了原始数组,导致程序出现了难以追踪的问题。这让他意识到,清楚掌握哪些数组方法会改变原数组、哪些不会,是每个JavaScript开发者必备的技能。今天,我们就来彻底理清这个知识点。

会改变原数组的方法(破坏性方法)

1. 增删元素三剑客

const team = ['杨涛', '李四', '王五'];

// push - 尾部添加
team.push('赵六'); 
console.log(team); // ['杨涛', '李四', '王五', '赵六']

// pop - 尾部删除
team.pop();
console.log(team); // ['杨涛', '李四', '王五']

// shift - 头部删除
team.shift();
console.log(team); // ['李四', '王五']

// unshift - 头部添加
team.unshift('张三');
console.log(team); // ['张三', '李四', '王五']

转存失败,建议直接上传图片文件

提醒:"这四个方法都会直接修改原数组,并返回被添加/删除的元素。"

2. 排序与反转

const numbers = [3, 1, 4, 2];

// sort - 排序
numbers.sort();
console.log(numbers); // [1, 2, 3, 4]

// reverse - 反转
numbers.reverse();
console.log(numbers); // [4, 3, 2, 1]

3. 强大的splice

    const members = ['杨涛', '李四', '王五', '赵六'];

    // 删除并添加元素
    const removed = members.splice(1, 2, '张三', '钱七');
    console.log(removed); // ['李四', '王五'] 
    console.log(members); // ['杨涛', '张三', '钱七', '赵六']

笔记:"splice堪称数组手术刀,可以任意位置删除、添加或替换元素。"

不会改变原数组的方法(非破坏性方法)

1. 查询类方法

    const staff = ['杨涛', '李四', '王五'];

    // concat - 连接数组
    const newStaff = staff.concat(['赵六']);
    console.log(staff); // ['杨涛', '李四', '王五'] (未改变)
    console.log(newStaff); // ['杨涛', '李四', '王五', '赵六']

    // slice - 截取子数组
    const part = staff.slice(1, 3);
    console.log(part); // ['李四', '王五']
    console.log(staff); // ['杨涛', '李四', '王五'] (未改变)

2. 迭代类方法

    const scores = [85, 92, 78];

    // map - 映射新数组
    const newScores = scores.map(score => score + 5);
    console.log(scores); // [85, 92, 78] (未改变)
    console.log(newScores); // [90, 97, 83]

    // filter - 过滤数组
    const highScores = scores.filter(score => score > 80);
    console.log(highScores); // [85, 92]
    console.log(scores); // [85, 92, 78] (未改变)

心得:"这些方法都会返回新数组,非常适合函数式编程。"

容易混淆的特殊情况

1. fill方法的双重性

    const arr = [1, 2, 3, 4];
    const newArr = arr.fill(0, 1, 3); 
    console.log(arr); // [1, 0, 0, 4] (原数组被修改)
    console.log(newArr); // [1, 0, 0, 4] (返回的是修改后的原数组)

2. sort的比较函数

    const users = [
      { name: '杨涛', age: 28 },
      { name: '李四', age: 25 }
    ];

    // 会改变原数组
    const sortedUsers = users.sort((a, b) => a.age - b.age);
    console.log(users === sortedUsers); // true (是同一个数组)

最佳实践建议

通过项目实践,杨涛总结出以下经验:

  1. 明确意图:如果确实需要修改原数组,使用破坏性方法
  2. 保持不可变:多数情况下优先使用非破坏性方法
  3. 性能权衡:对大型数组,适当使用破坏性方法可减少内存占用
  4. 清晰注释:使用破坏性方法时添加注释说明
    // 好的实践:使用扩展运算符创建新数组
    const original = ['杨涛', '李四'];
    const updated = [...original, '王五'];

    // 需要修改原数组时的注释
    // 注意:此操作会直接修改original数组
    original.push('赵六');

现代JavaScript的不可变方案

ES6及后续版本提供了更多保持不可变性的方式:

    // 使用Object.freeze防止意外修改
    const frozenArray = Object.freeze(['杨涛', '李四']);
    // frozenArray.push('王五'); // 报错

    // 使用新的with方法(ES2023)
    const newArray = frozenArray.with(1, '王五'); 
    console.log(frozenArray); // ['杨涛', '李四'] (未改变)
    console.log(newArray); // ['杨涛', '王五']

实用速查表

为方便记忆,整理了这张表格:

方法是否修改原数组返回值
push/pop添加/删除的元素
shift/unshift添加/删除的元素
splice被删除的元素数组
sort/reverse排序后的原数组
fill修改后的原数组
concat新数组
slice子数组
map/filter新数组
reduce累计结果
with修改后的新数组(ES2023)

总结

"理解数组方法的破坏性就像掌握外科手术器械的区别,"在团队分享时说,"有些像手术刀会直接改变组织,有些像检查仪器则保持原样。"

记住这个原则:

  • 会改变原数组:push/pop/shift/unshift/splice/sort/reverse/fill/copyWithin
  • 不会改变原数组:concat/slice/map/filter/reduce/with/find/findIndex等

掌握这些区别后,你将能更自信地操作数组,避免意外的副作用,写出更健壮的JavaScript代码。