数组
1. ...
扩展运算符可以直接作用于数组
...[2,3,4] // 相当于 2,3,4
console.log(...[2,3,4])
(1). 我们常用于函数调用或者数组拷贝
const arr1 = [{name : 'a'},{name : 'b'}]
const arr2 = [...arr1]
arr2[0] === arr1[0] // true
arr2 === arr1 // false 浅拷贝
(2)我们常常依赖apply将数组作为实参传入,现在不用了
Math.max.apply(null, [14, 3, 77])
// ES6 的写法
Math.max(...[14, 3, 77])
(3). 与解构赋值配合使用(这部分很少用)
const [a,...arr] = [1,2,3,4,5]
console.log(a) // 1
console.log(arr) // [2,3,4,5]
注意 : ...arr用于解构赋值时只能位于末尾位置,其它位置会报错
(4). 字符串转为数组
...可以将字符串转为真正的数组 更重要的是 那就是能够正确识别四个字节的 Unicode 字符
[...'hello']
// [ "h", "e", "l", "l", "o" ]
(5). Iterator对象
任何定义了遍历器(Iterator)接口的对象,都可以使用扩展运算符转为真正的数组
let nodeList = document.querySelectorAll('div');
let array = [...nodeList];
dom方法返回的数组不是真正的数组,而是类数组对象,此时可以使用可扩展运算符转为真正的数组,因为它部署了iterator接口(arguments也部署了该接口)。
而对于普通的类数组,这是无效的
let arrayLike = {
'0': 'a',
length: 1
};
// TypeError: Cannot spread non-iterable object.
let arr = [...arrayLike];
(6). Map和Set结构,*函数
Map与Set的构造函数,可以直接传入一个数组对象,返回的keys是一个遍历器对象
可以直接使用...
说到底,...运算符是直接调用iterator接口的
let map = new Map([
[1, 'one'],
[2, 'two'],
[3, 'three'],
]);
console.log(...map.keys())
gennrator函数运行后,也是返回一个遍历器对象,因此,也可直接出结果
const go = function*(){
yield 1;
yield 2;
yield 3;
};
[...go()] // [1, 2, 3]
对这个遍历器对象执行扩展运算符,就会将内部遍历得到的值,转为一个数组
2. Array.from
Array.from方法用于将两类对象转为真正的数组:
- 类似数组的对象(array-like object)
- 可遍历(iterable)的对象(包括 ES6 新增的数据结构 Set 和 Map)。
let arrayLike = {
'0': 'a',
'1': 'b',
'2': 'c',
length: 3
};
var arr1 = [].slice.call(arrayLike); // ['a', 'b', 'c']
let arr2 = Array.from(arrayLike); // ['a', 'b', 'c']
实际上,对于其他类数组对象如 : arguments、NodeList都可以使用该方法
iterator接口也可以,不过我觉得...比较方便吧,但...不能将类数组转为数组
let namesSet = new Set(['a', 'b'])
Array.from(namesSet) // ['a', 'b']
Array.from还接受第二个参数,类似map,用于对每个元素进行处理
Array.from(arrayLike, x => x * x);
// 等同于
Array.from(arrayLike).map(x => x * x);
Array.from([1, 2, 3], (x) => x * x)
利用这个方法可以进行很多骚操作。如取出一组 DOM 节点的文本内容
const spans = document.querySelectorAll('span.name');
// map()
let names1 = Array.prototype.map.call(spans, s => s.textContent);
// Array.from()
let names2 = Array.from(spans, s => s.textContent)
Array.from()还可以接受第三个参数,即thisArg
3. Array.of()
Array.of接受一组值(类似call),然后将其转为数组
Array.of(3, 11, 8) // [3,11,8]
但需要注意的是,这个方法具有重载特性
Array() // [] 没有参数,返回空数组
Array(3) // [, , ,] 一个参数,指定数组长度
Array(3, 11) // [3, 11] 大于等于2个参数,返回数组
Array.of基本上可以用来替代Array()或new Array()
这个方法可以这样模拟
function ArrayOf(){
return [].slice.call(arguments);
}
4. Array.prototype.copyWithin
数组实例的copyWithin()方法,在当前数组内部,将指定位置的成员复制到其他位置(会覆盖原有成员),然后返回当前数组。不是纯函数
它接受以下参数
- target(必须) 替换起始索引
- start(可选):从该位置开始读取数据,默认为 0。如果为负值,表示从末尾开始计算。
- end(可选):到该位置前停止读取数据,默认等于数组长度。如果为负值,表示从末尾开始计算。
let copyArray = [1,2,3,4,5,6]
copyArray.copyWithin(0,3) // [4,5,6,4,5,6]
5. Array.prototype.find与Array.prototype.findIndex
数组实例的find方法,用于找出第一个符合条件的数组成员。接受一个filter函数,找不到符合条件的成员,则返回undefined
数组实例的findIndex方法的用法与find方法非常类似,返回下标
6. Array.prototype.fill
填充,从这个名字知道意思了吧
['a', 'b', 'c'].fill(7,0,1)
注意,当参数为对象时,
7. Array.prototype.entries | keys | value
这三个方法返回一个遍历器对象,可以用for...of遍历
不同的是
- entries 返回键值对的迭代器 // [index,value]
- keys 返回索引的迭代器 // {value :0 // 这是索引,done:false }
- values 返回值的迭代器 // { value : 1 //这是值, done : false}
8. Array.prototype.includes()
Array.prototype.includes方法返回一个布尔值,表示某个数组是否包含给定的值,与字符串的includes方法类似
接受两个参数
- target
- start 从哪个索引开始查找
[1, 2, 3].includes(2,1) // true
没有该方法之前,我们通常使用数组的indexOf方法,检查是否包含某个值。
if (~arr.indexOf(element)) {
...
}
indexOf方法有两个缺点
- 不够语义化
- 对于NaN使用全等判断 往往
[NaN].indexOf(NaN) // -1
includes使用的是不一样的判断算法,就没有这个问题。
9. Array.prototype.flat,flatMap()
该方法可以对数组进行降维打击
[1, 2, [3, 4]].flat() // [1, 2, 3, 4]
flat()方法默认降维为1层
它可以接受一个参数,表示要降维的层数
[1, 2, [3, [4, 5]]].flat(2)
// [1, 2, 3, 4, 5]
如果原数组有空位,flat()方法会跳过空位。
[1, 2, , 4, 5].flat()
// [1, 2, 4, 5]
flatMap()方法对原数组的每个成员执行map函数
[2, 3, 4].flatMap((x) => [x, x * 2])
// [2, 4, 3, 6, 4, 8]
此外,它还可以接受第二个参数thisArg
10. 数组的空位
数组的空位指,数组的某一个位置没有任何值。这常出现在delete操作后
比如,Array构造函数返回的数组都是空位。
Array(3) // [, , ,]
要注意的是ES5对空位的处理
- forEach(), filter(), reduce(), every() 和some()都会跳过空位。
- map()会跳过空位,但会保留这个值
- join()和toString()会将空位视为undefined,而undefined和null会被处理成空字符串。
ES6 则是明确将空位转为undefined。
- Array.from方法会将数组的空位,转为undefined,也就是说,这个方法不会忽略空位。
- 扩展运算符(...)也会将空位转为undefined。
- copyWithin()会连空位一起拷贝。
- fill()会将空位视为正常的数组位置。
- for...of循环也会遍历空位。
- entries()、keys()、values()、find()和findIndex()会将空位处理成undefined。
11. sort的稳定性
排序稳定性(stable sorting)是排序算法的重要属性,指的是排序关键字相同的项目,排序前后的顺序不变。
常见的排序算法之中,插入排序、合并排序、冒泡排序等都是稳定的,堆排序、快速排序等是不稳定的。不稳定排序的主要缺点是,多重排序时可能会产生问题。假设有一个姓和名的列表,按照“先姓,后名”进行排序。开发者可能会先按名字排序,再按姓氏进行排序。如果排序算法是稳定的,这样也可以达到“先姓,后名”的排序效果。如果是不稳定的,就不行。
ES2019 明确规定,Array.prototype.sort()的默认排序算法必须稳定。这个规定已经做到了,现在 JavaScript 各个主要实现的默认排序算法都是稳定的。
网友评论