Array

作者: zdxhxh | 来源:发表于2020-01-16 10:21 被阅读0次

数组

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 各个主要实现的默认排序算法都是稳定的。

相关文章

网友评论

      本文标题:Array

      本文链接:https://www.haomeiwen.com/subject/nicfzctx.html