还分不清 splice 和 slice 吗

309 阅读6分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第2天,点击查看活动详情


读完本文,你将彻底弄清以下问题。

  1. splice 接收几个参数?分别有哪几种用法?
  2. spliceslice 的区别在哪?
  3. slicesubtringsubstr 之间的区别又在哪?

这几种方法都涉及切片(切割),但又不仅相同,因此我把这几种数组和字符串方法放到一篇文章里面讲。

首先,这几种方法属于不同的数据类型。

  • 数组方法:slicesplice
  • 字符串方法:slicesubtringsubstr

注意,slice 方法同时可用于字符串和数组中,substr 属于即将被废除但暂时还能使用(deprecated)的方法,不建议使用。

字符串方法都是非原地修改方法吗,因为JS 中字符串不可变(即在不改变原变量地址的情况下,无法修改原字符串的值)!

splice

splice 的功能很强大,它可以在数组中 删除、替换、插入、添加 一个或多个元素,是一个 原地修改 方法,所谓 “原地”,就是它会影响原数组。

splice 接收三个参数,且这三个参数都是 可选的,这意味着参数不同,用法不同,为了方便大家记忆和学习,我 按照实参数量 来分情况叙述 splice 的用法。

1. 参数个数为 1

1.1、语法

arr.splice(i)

当 splice 方法的参数只有 1 个的时候(i),表示删除数组中索引为 ii 之后的所有元素。返回删除的元素,数组原地修改。其中,参数 i 是整数。
对于 i 分情况:

  • i 为非负整数:删除数组中索引为 ii 之后位置上所有的元素
  • i 为负整数:索引从后往前计算,最后一位索引是 -1,倒数第二位是 -2,依次类推。删除 ii 之后的所有元素。

1.2、举例

删除数组中最后三个元素

var a = [1, 2, 3, 4, 5]
a.splice(-3)
console.log(a) // [1, 2]

清空数组

var a = [1, 2, 3, 4, 5]
a.splice(0) // 或 a.splice(-5)
console.log(a) // []

2. 参数个数为 2

2.1、语法

arr.splice(i, j)

当 splice 方法有两个参数时,两个参数必须均为整数。表示从数组中索引为 i 开始删除,一共删除 j 个元素。

2.2、示例

删除数组中开头的 3 个元素

var a = [1, 2, 3, 4, 5]
a.splice(0, 3)
console.log(a) // [4, 5]

只留下数组值第一个和最后一个元素

var a = [1, 2, 3, 4, 5]
a.splice(1, a.length - 2)
console.log(a) // [1, 5]

从索引 -2 的位置开始删除 2 个元素

var a = [1, 2, 3, 4, 5]
a.splice(-2, 2)
console.log(a) // [1, 2, 3]

3. 参数个数为 3 个及以上

3.1、语法

a.splice(i, j, e1, e2, ...)
  • i:整数,表示索引的起始位置
  • j:整数,表示删除的个数
  • e1、e2、...:删除相应元素之后要添加的元素

当 splice 方法有 3 个参数时,表示从索引为 i 位置开始删除 j 个元素,然后在从 i 位置添加 e1,e2,...,返回删除的元素,原地修改。

  • j 为 0,则表示一个元素也不删除,则元素从 i 前一个位置开始插入
  • j > 0,则表示从 i 位置开始(包括 i 位置)删除 j 个元素,然后从 i 后面开始插入。

3.2、示例

替换索引位置为 2 的元素的值为 'aaa'

var a = [1, 2, 3, 4, 5]
a.splice(2, 1, 'aaa')
console.log(a) // [1, 2, 'aaa', 4, 5]

a.splice(2, 1, 'aaa') 表示从索引为 2 开始,删除 1 个元素,并插入 'aaa'(即实现了替换,替换了索引为 2 的元素)。

往数组中索引为 1 的位置插入元素 'a''b'c

var a = [1, 2, 3, 4, 5]
a.splice(1, 0, 'a', 'b', 'c')
console.log(a) 
// [1, 'a', 'b', 'c', 2, 3, 4, 5]

往数组中索引为 -2 的位置插入元素 'a''b'

var a = [1, 2, 3, 4, 5]
a.splice(-2, 0, 'a', 'b')
console.log(a) 
// [1, 2, 3, 'a', 'b', 4, 5]

往数组的开头插入 3 个元素。

var a = [1, 2, 3]
a.splice(0, 0, 'a', 'b', 'c')
console.log(a) 
// ['a', 'b', 'c', 1, 2, 3]

往数组的末尾插入 3 个元素。

var a = [1, 2, 3]
a.splice(a.length, 0, 'a', 'b', 'c')
console.log(a) 
// [1, 2, 3, 'a', 'b', 'c']

slice

slice 可同时用于数组和字符串,是一个非原地操作方法,即不影响原数组和字符串。

slice 意为 “切片”,顾名思义,就是从数组和字符串中切出一部分内容出来。

slice 同时可用于数组和字符串,以字符串为例。

1. 语法

str.slice(i, j)
// 或 arr.slice(i, j)

参数:

  • i:要截取的字符串的起始位置,包括该位置的字符
  • j:要截取的字符串的末尾位置,不包括该位置的字符

总结起来就是截取一个字符串的 “前闭后开” 区间的字串。

前闭后开区间指 [1, 3),该区间包含前边界,但是不包括后边界。例如 Math.random 方法就是返回 [0,1) 的前闭后开区间的数字。

2. 举例

取出字符串剔除了首个和末尾的子串:

var str = 'abcdef'
var sub = str.slice(1, -1)
console.log(sub) // 'bcde'

类似的,slice 也能作用于数组:

var arr = [1, 2, 3, 4, 5]
var sub = arr.slice(1, 4)
console.log(sub) // [2, 3, 4]

3. 特殊使用

  1. slice 可以把伪数组转换为真实的数组类型。

语法:

// fakeArr 为伪数组类型
Array.prototype.slice.call(fakeArr)
// 或者
[].slice.call(fakeArr)

举例:

function foo() {
  console.log(Array.prototype.slice.call(arguments))
  console.log([].slice.call(arguments))
}

foo(1, 2, 3)

// 打印结果
// [1, 2, 3]
// [1, 2, 3]
  1. slice 可以对数组进行深拷贝
let arr1 = [123], arr2 = arr1.slice()
arr2.pop()
console.log(arr1) // [1, 2, 3]
console.log(arr2); // [1, 2]

subtring

subtring(i, j) 是截取字符串,截取字符串的 [i, j) 区间的字串,且 ij 不能为负数。属于非原地方法,返回截取的子串。

let str = 'abcde'
str.substring(1, 4) // bcd

substr

substr(i, count) 也是截取字符串,不同的是它截取从指定位置 i 开始的,一共 count 个字符串。i 可以为负数,表示倒数第几个。属于非原地方法,返回截取的子串。

let str = 'abcde'
str.substr(1, 4) // bcde

!W3C 规定 substr 已经不属于 JS 的核心和规范了,虽然当前可用,但未来随时会被废弃,不要使用它!

总结

了解了四种方法的使用,现在来总结以下。

  1. 四种方法中,只有 splice 是原地操作方法,字符串方法没有原地方法。
  2. spliceslice 的区别,splice 的功能更强大,可以用于数组中元素的删除、替换、添加、插入。slice 是非原地算法,功能是截取字符串,获取子串。
  3. slice 是切片,可用于数组和字符串。
  4. slice(i, j)substring(i, j) 的区别,slice 可接收负数为参数,而后者不可以,传入负数会变成 0
  5. substring(i, j)substr(i, count) 的区别,前者第二个参数是截取字符串的后边界,后者第二参数是截取的字串的长度。
  6. 与 slice 和 substr 方法不同的是,substring 不接受负的参数