Array

创建数组

  • 使用 Array 构造函数
  • 数组字面量

ES6 在 Array 构造函数上新增了两个用于创建数组的静态方法:from()of()

from() 用于将类数组解构转换为数组实例
参数:第一个参数是一个类数组对象,即任何可迭代的结构,或者有一个 length 属性和可索引元素的结构;第二个参数为可选,是一个函数,新数组中的每个元素都会执行该回调函数;第三个参数为可选,指定执行回调函数时的 this(箭头函数不适用)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
// 字符串会被拆分成单字符数组
Array.from('Matt') // ['M','a','t','t']

// 可以将集合和映射转换为一个新数组
const a = new Map().set(1,2).set(3,4)
const b = new Set().add(1).add(2).add(3).add(4)

Array.from(a) // [[1,2],[3,4]]
Array.from(b) // [1,2,3,4]

// 对现有数组进行浅复制
const ai = [1,2,3,[4,5]]
const a2 = Array.from(a1)

a1 === a2 // false
a1[3] === a2[3] // true

// 可以使用任何可迭代对象
const iter = {
*[Symbol.iterator](){
yield 1;
yield 2;
yield 3;
yield 4
}
}
Array.from(iter) // [1,2,3,4]

// arguments 对象转换为数组
function getArgs2Array(){
return Array.from(arguments)
}
getArgs2Array(1,2,3,4) // [1,2,3,4]

// 转换带有必要属性的自定义对象(类数组)
const obj = {
0: 1,
1: 2,
2: 3,
3: 4,
length: 4
}
Array.from(obj) // [1,2,3,4]

// 带第二个参数
const a1 = [1,2,3,4]
const a2 = Array.from(a1, x => x*2 ) // [2,4,6,8]
const a3 = Array.from(a1, function(x){return x*this.exponent}, {expooent: 2}) // [2,4,6,8]

of() 用于将一组参数转换为数组实例

1
2
3
4
5
6
// Array.of() 和 Array 构造函数的区别在于处理整数参数
Array.of(7) // [7]
Array.of(1,2,3) // [1,2,3]

Array(7) // [ , , , , , , ] 7个空位(empty),不是7个undefined
Array(1,2,3) // [1,2,3]

数组空位

ES6 新增方法普遍将这些空位当成存在的元素,值为 undefined
ES6 之前的方法会忽略空位,但具体行为因方法而异

由于行为不一致和存在性能隐患,因此实践中要避免使用数组空位。如果确实需要空位,可以显示的用 undefined 值替代

复制和填充方法

ES6 新增:(以下两个方法都不会改变数组的大小)
copyWithin():浅复制数组的一部分到同一数组中的另一个位置,并返回它
语法:

1
arr.copyWithin(target,start(可选),end(可选))

参数:
target: 复制内容到该位置
start: 开始复制元素的起始位置。如果不写,默认值为0
end: 开始复制元素的结束位置(不包括该位置)。如果不写,会一直到末尾

1
2
3
4
5
let ints = [0,1,2,3,4,5,6,7,8,9]
ints.copyWithin(4,0,3) // [0,1,2,3,0,1,2,7,8,9]
// copyWithin() 的负数和 fill() 的负数处理是一样的
inst.copyWithin(-4,-7,-3) // [0, 1, 2, 3, 4, 5, 3, 4, 5, 6]
// 超出边界的处理也和 fill() 相同

fill():填充
参数:填充内容,开始索引(可选),结束索引(可选,不包括该位置)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
const ary = [0, 0, 0, 0, 0]

// 不指定起始索引
ary.fill(5) // [5, 5, 5, 5, 5]

ary.fill(0) // 重置 ary,以下每次示例默认会重置,但不再写

// 指定索引
ary.fill(6,2,4) // [0, 0, 6, 6, 0]

// 负数索引(负数索引会替换为 总长度+负数 )
ary.fill(2,-4,-2) // -> ary.fill(2,1,3) -> [0,2,2,0,0]

// 超出数组边界、零长度和方向相反的索引范围会被忽略
ary.fill(2,10,15) // [0,0,0,0,0]
ary.fill(2,-10,-6) // [0,0,0,0,0]
ary.fill(2,4,2) // [0,0,0,0,0]
ary.fill(2,2,10) // [0,0,2,2,2]

排序方法

sort()
默认情况下,sort() 会按照升序重新排列数组元素,即最小的值在前面,最大的值在后面。为此,sort() 会在每一项上调用 String() 转型函数,然后比较字符串来决定顺序。即使数组的元素都是数值,也会先把数组转换为字符串再比较、排序:

1
2
3
let values = [0, 1, 5, 10, 15]
values.sort()
alert(values) // 0,1,10,15,5

由于字符串 “10” 在字符串 “5” 的前头,所以 10 还是会排到 5 前面。为此,sort() 方法可以接收一个比较函数,用于判断哪个值应该排在前面

revuerse() 和 sort() 都返回调用他们的数组的引用

操作方法

concat()
返回值:
返回一个新数组,不会改变原数组

1
2
3
4
let colors = ['red','green','blue']
let colors2 = colors.concat('yellow',['black','brown'])
console.log(colors) // ['red','green','blue']
console.log(colors2) // ['red','green','blue','yellow','black','brown']

以上例子中,concat() 参数 ['black','brown'] 被 “打平” 了。打平数组参数的行为可以重写,方法是在参数数组上指定一个特殊的符号:Symbol.isConcatSpreadable。这个符号接收布尔值,true 为强制打平(包括类数组对象),false 为阻止打平

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
let colors = ['red', 'green', 'blue']
let newColors = ['black', 'brown']
let moreNewColors = {
[Symbol.isConcatSpreadable]: true,
length: 2,
0: 'pink',
1: 'cyan'
}

newColors[Symbol.isConcatSpreadable] = false
// 不打平
let colors2 = colors.concat('yellow', newColors)
// 打平
let colors3 = colors.concat(moreNewColors)
console.log(colors2); ['red', 'green', 'blue', 'yellow',['black','brown']]
console.log(colors3); ['red', 'green', 'blue', 'pink', 'cyan']

splice()
返回值:
被删除的元素(如果没有删除元素,则返回空数组)。会改变原始数组

归并方法

reduce() & reduceRight()

reduce() 方法从数组第一项开始遍历到最后一项;reduceRight() 是从最后一项开始遍历至第一项

参数:
1、每一项都会运行的归并函数。该函数接收4个参数:
1、上一个归并值
2、当前项
3、当前项的索引
4、数组本身
2、归并起点的初始值

如果提供归并值,则第一次迭代会以数组的第一项作为归并值,第二项作为当前项

1
2
3
let values = [1,2,3,4,5]
let sum = values.reduce((prev, cur, index, array) => prev + cur) // 加法求和
console.log(sum) // 15

定型数组

定型数组(typed array)是 ECMAScript 新增的结构,目的是提升向原生库传输数据的效率。实际上,JavaScript 并没有 “TypeArray” 类型,它所指的其实是一种特殊的包含数值类型的数组

ArrayBuffer

ArrayBuffer 是所有定型数组及视图引用的基本单位

ArrayBuffer() 是一个普通的 JavaScript 构造函数,可用于在内存中分配特性数量的字节空间

1
2
const buf = new ArrayBuffer(16) // 在内存中分配16字节
alert(buf.byteLength) // 16

ArrayBuffer 一经创建就不能再调整大小。不过,可以使用 slice() 复制其全部或部分到一个新实例中:

1
2
3
const buf1 = new ArrayBuffer(16)
const buf2 = buf1.slice(4,12)
alert(buf2.byteLength) // 8
  • ArrayBuffer 在分配失败时会抛出错误
  • ArrayBuffer 分配的内存不能超过 Number.MAX_SAFE_INTEGER(2^^53-1) 字节
  • 声明 ArrayBuffer 会将所有二进制位初始化位 0
  • 通过声明 ArrayBuffer 分配的堆内存可以被当成垃圾回收,不用手动释放

不能仅通过对 ArrayBuffer 的引用就读取或写入其内容。要读取或写入 ArrayBuffer,就必须通过视图。视图有不同的类型,但引用的都是 ArrayBuffer 中存储的二进制数据

DateView

Map

Map 是 ES6 新增的一种集合类型,为 JavaScript 带来了真正的键/值存储机制

基本API

顺序与迭代

选择 Object 还是 Map

迭代与扩展操作符