当前位置:首页 > 技术文章 > 正文内容

揭秘JavaScript数组神器slice():不修改原数组的5个实用技巧

zonemu5小时前技术文章3

你是不是也遇到过这样的坑?辛辛苦苦处理数组,结果不小心把原数组改得面目全非?今天要给大家介绍的slice()方法,就是JavaScript数组操作中的"安全卫士"——既能灵活处理数组,又不会修改原数据!无论是复制数组、提取子数组,还是处理DOM集合,它都能轻松搞定。话不多说,跟着我一起解锁这个方法的全部技能吧~

初识slice():数组的"无损手术刀"

slice()方法就像一把精密的手术刀,能从数组中"切取"部分元素,却不会对原数组造成任何伤害。它的语法超级简单:

arr.slice([start[, end]])
  • start(可选):起始索引,支持负数(从数组末尾计数,比如-1就是最后一个元素)
  • end(可选):结束索引(不包含该位置元素),同样支持负数
  • 返回值:新数组,包含从start到end(不含end)的元素

核心特性原数组不变!原数组不变!原数组不变!(重要的事情说三遍)

举个栗子:

const fruits = ['', '', '', '', ''];
const citrus = fruits.slice(2, 4); // 从索引2开始,到索引4结束(不含4)
console.log(citrus); // ['', '']
console.log(fruits); // ['', '', '', '', ''] 原数组完好无损!

5个实战技巧:slice()让你代码更优雅

1 一键复制数组,告别"引用陷阱"

想复制一个数组又怕修改新数组影响原数组?slice()无参数调用就能搞定浅拷贝:

const original = [1, 2, 3, 4];
const copy = original.slice(); // 等价于 original.slice(0)
copy.push(5);
console.log(original); // [1,2,3,4] 原数组没变化!
console.log(copy); // [1,2,3,4,5] 新数组自由修改

2 提取子数组,轻松实现分页功能

前端分页展示数据时,用slice()截取指定范围元素,简单又高效:

const allData = [1, 2, 3, ..., 100]; // 假设有100条数据
const pageSize = 10;
const currentPage = 3;
// 计算起始索引:(当前页-1)*每页条数
const start = (currentPage - 1) * pageSize;
const pageData = allData.slice(start, start + pageSize); // 第3页数据:[21~30]

3 类数组转数组,DOM操作不再头疼

DOM方法(如querySelectorAll)返回的NodeList是"类数组",没有数组方法?用slice()一键转换:

// 获取所有div元素(类数组)
const divs = document.querySelectorAll('div');
// 转换为真正的数组,就能用forEach、map等方法啦!
const divArray = Array.prototype.slice.call(divs);
divArray.forEach(div => console.log(div));

4 函数参数处理,arguments变数组

函数内的arguments对象也是类数组,用slice()转为数组后操作更方便:

function sum() {
  // 将arguments转为数组,才能用reduce求和
  const args = Array.prototype.slice.call(arguments);
  return args.reduce((total, num) => total + num, 0);
}
sum(1, 2, 3); // 6

5 负数索引,从后往前取元素

想取数组最后n个元素?负数索引帮你省去arr.length - n的麻烦:

const numbers = [1, 2, 3, 4, 5];
numbers.slice(-3); // [3,4,5] 取最后3个
numbers.slice(2, -1); // [3,4] 从索引2到倒数第1个(不含)

避坑指南:这些"坑"你一定踩过!

浅拷贝陷阱:引用类型数据会"联动"

敲黑板slice()是浅拷贝,当数组包含对象/数组等引用类型时,修改新数组会影响原数组:

const arr = [{ name: '张三' }, 2, 3];
const copy = arr.slice();
copy[0].name = '李四'; // 修改新数组的对象属性
console.log(arr[0].name); // "李四"  原数组也被改了!

解决办法:如果需要完全独立的数组,需用深拷贝(如JSON.parse(JSON.stringify(arr))或递归拷贝)。

别和splice()搞混!一张表分清区别

很多小伙伴分不清slice()splice()?记住这个对比表,面试再也不怕问:

特性

slice()

splice()

是否修改原数组

不修改(安全)

直接修改(危险)

返回值

新数组(截取的元素)

被删除的元素组成的数组

参数

start, end(结束索引)

start, deleteCount, ...items(删除/添加元素)

用途

截取、复制数组

添加/删除/替换元素

性能PK:slice()到底有多快?

根据JS性能测试数据,在Chrome等现代浏览器中:

  • slice()复制数组的速度比for循环快2~3倍
  • Array.from()和扩展运算符[...arr]略快(尤其大数据量时)

测试代码(100万长度数组复制):

const arr = new Array(1000000).fill(1);
console.time('slice');
const copy = arr.slice(); // slice()复制:约12ms
console.timeEnd('slice');

console.time('for');
const copy2 = [];
for (let i = 0; i < arr.length; i++) copy2[i] = arr[i]; // for循环:约30ms
console.timeEnd('for');

结论:处理大数据时,slice()是更优选择!

真实案例:Vue源码中的slice()应用

Vue的nextTick方法中,用slice()安全获取回调函数列表,避免执行过程中回调被修改:

// Vue源码片段(简化版)
const callbacks = [];
function flushCallbacks() {
  // 复制当前回调列表,防止执行中回调被修改
  const copies = callbacks.slice(); 
  callbacks.length = 0; // 清空原列表
  copies.forEach(cb => cb()); // 执行复制的回调
}

这样即使在回调执行中新增回调,也不会影响当前批次的执行,保证逻辑安全~

总结:slice()的5个核心优势

  1. 安全无副作用:不修改原数组,避免意外数据污染
  2. 灵活截取:支持正数索引、负数索引,轻松提取任意片段
  3. 类数组转换:DOM集合、arguments等类数组秒变数组
  4. 性能优异:现代浏览器优化加持,大数据处理更快
  5. 简洁优雅:一行代码搞定复制、截取,可读性拉满

下次处理数组时,别再用splice()"暴力操作"啦!试试slice(),让你的代码更安全、更优雅~

互动话题:你在项目中用slice()解决过什么问题?评论区分享你的实战经验吧!

(注:文中图片来源已标注,部分代码示例参考MDN文档及Vue源码)

相关文章

vue3源码分析——实现组件通信provide,inject

引言<<往期回顾>>vue3源码分析——rollup打包monorepovue3源码分析——实现组件的挂载流程vue3源码分析——实现props,emit,事件处理等vue3源...

Vue2的16种传参通信方式(vue传参数)

前言先直入主题列出有哪些传参方式,下面再通过事例一一讲解。props(父传子)$emit与v-on (子传父)EventBus (兄弟传参).sync与update: (父子双向)v-model (父...

迁移GIT仓库并带有历史提交记录(git 迁移仓库)

迁移git仓库开发在很多时候,会遇到一个问题。GIT仓库的管理,特别是仓库的迁移。我需要保留已有的历史记录,而不是重新开发,重头再来。我们可以这样做:使用--mirror模式会把本地的分支都克隆。//...

GIT最佳实践,高效提升多团队协同开发效率

多个团队共同维护同一个微服务模块时,经常出现A团队已发布的功能,B团队提交测发布出现冲突或缺失,如何有效解决多团队共同维护的问题呢?常用的版本管理工具有GIT、SVN,这两种版本管理工具,各有千秋;虽...

编写简单的.gitlab-ci.yml打包部署项目

服务器说明:192.168.192.120:项目服务器192.168.192.121:GitLab为了可以使用gitlab的cicd功能,我们需要先安装GitLab Runner安装GitLab Ru...

jenkins+gitlab 实现自动化部署(gitlab触发jenkins)

目录1、安装jdk,要记住安装路径2、安装maven,要记住安装路径3、安装git,要记住安装路径4、安装gitlab5、安装jenkins(centos7)创建安装目录下载通用war包启动和关闭Je...