JS数组
本文简单介绍了一些常用的JS数组操作,内容较为零散。
基本操作
at
有些编程语言允许我们使用负数索引来实现获取数组的最后一个元素,但这在JS中行不通,在JS中,我们可以使用at:
1 | let fruits = ["Apple", "Orange", "Plum"]; |
换句话说,arr.at(i)
:
- 如果
i >= 0
,则与arr[i]
完全相同。 - 对于
i
为负数的情况,它则从数组的尾部向前数。
增添元素
push(...items)
在末端添加items
项。pop()
从末端移除并返回该元素。shift()
从首端移除并返回该元素。unshift(...items)
从首端添加items
项。
splice
1 | arr.splice(start[, deleteCount, elem1, ..., elemN]) |
从索引 start
开始修改 arr
:删除 deleteCount
个元素并在当前位置插入 elem1, ..., elemN
。最后返回被删除的元素所组成的数组。
1 | arr.splice(1, 1); // 从索引 1 开始删除 1 个元素 |
slice
1 | arr.slice([start], [end]) |
它会返回一个新数组,将所有从索引 start
到 end
(不包括 end
)的数组项复制到一个新的数组。start
和 end
都可以是负数,在这种情况下,从末尾计算索引。
我们也可以不带参数地调用它:arr.slice()
会创建一个 arr
的副本。其通常用于获取副本,以进行不影响原始数组的进一步转换。
concat
1 | arr.concat(arg1, arg2...) |
它接受任意数量的参数 —— 数组或值都可以。
结果是一个包含来自于 arr
,然后是 arg1
,arg2
的元素的新数组。
1 | let arr = [1, 2]; |
搜索
find
寻找一个匹配的元素
1 | let result = arr.find(function(item, index, array) { |
还有findIndex
和findLastIndex
返回匹配索引。
filter
寻找所有匹配的元素
1 | let results = arr.filter(function(item, index, array) { |
转换
map
最常用的方法,对每个元素都调用函数,然后返回结果数组。
1 | let result = arr.map(function(item, index, array) { |
sort
对原数组进行排序。
1 | arr.sort( (a, b) => a - b ); |
split/join
1 | let names = 'Bilbo, Gandalf, Nazgul'; |
1 | let arr = ['Bilbo', 'Gandalf', 'Nazgul']; |
Array.isArray
Array.isArray(value)
检查 value
是否是一个数组,如果是则返回 true
,否则返回 false
。
数组的对象本质
在JS中只有8中基本数据类型,数组实际上是一种对象,真正特殊的是它们的内部实现。JavaScript 引擎尝试把这些元素一个接一个地存储在连续的内存区域,而且还有一些其它的优化,以使数组运行得非常快。但是,如果我们不像“有序集合”那样使用数组,而是像常规对象那样使用数组,这些就都不生效了。
下面的操作会使数组退化为对象:
1 | let fruits = []; // 创建一个数组 |
可迭代对象
为对象添加一个名为 Symbol.iterator
的方法(一个专门用于使对象可迭代的内建 symbol)。
这个方法需要返回一个有next
方法的对象,其返回的结果格式必须为 {done: Boolean, value: any}
,当 done=true
时,表示循环结束,否则 value
是下一个值。
1 | let range = { |
对于可迭代或类数组(有索引和length
属性)对象,我们可以使用Array.from
得到一个真正的数组,之后便可以调用方便的数组方法。
循环
数组有三种循环方式:
for (let i=0; i<arr.length; i++)
— 运行得最快,可兼容旧版本浏览器。for (let item of arr)
— (迭代器)现代语法,只能访问 items。for (let i in arr)
— (对象)永远别用。
length
数组中的length属性其实是其最大的数字索引值加一,如果我们减少它,则数组会发生不可逆截断。
清空数组的最简单方式就是arr.length = 0;
Object.keys(obj)
对于对象来说,我们使用的调用语法是 Object.keys(obj)
,而不是 obj.keys()
。因为对象是所有复杂结构的基础。
Object.*
方法返回的是“真正的”数组对象,而不只是一个可迭代对象。(虽然抽象程度变低了,但是是历史原因,就这样吧)
1 | let user = { |
Object.keys(user) = ["name", "age"]
Object.values(user) = ["John", 30]
Object.entries(user) = [ ["name","John"], ["age",30] ]
解构赋值
解构赋值可以简洁地将一个对象或数组拆开赋值到多个变量上。
解构对象的完整语法:
1
let {prop : varName = default, ...rest} = object
这表示属性
prop
会被赋值给变量varName
,如果没有这个属性的话,就会使用默认值default
。没有对应映射的对象属性会被复制到
rest
对象。解构数组的完整语法:
1
let [item1 = default, item2, ...rest] = array
数组的第一个元素被赋值给
item1
,第二个元素被赋值给item2
,剩下的所有元素被复制到另一个数组rest
。从嵌套数组/对象中提取数据也是可以的,此时等号左侧必须和等号右侧有相同的结构。
对“数组”的解构赋值可以范围拓展到可迭代对象上,如Map,Set等。
[guest, admin] = [admin, guest];// js用一行交换变量值