ES6学习笔记11:数组的扩展

数组的扩展

扩展运算符

定义

扩展运算符(spread)是三个点(...)。将一个数组转为用逗号分隔的参数序列

console.log(...[1,2,3]); // 1 2 3
console.log(1, ...[2,3,4],5); // 1 2 3 4 5
应用

扩展运算符主要用于函数调用。

function push(array, ...item){
  array.push(...item);
}

function add(x, y){
  return x + y;
}

const numbers = [4, 28];
add(...numbers); // 32
  • 扩展运算符和正常的函数参数可以结合使用,非常灵活。
function f(a,b,c,d,e){}
const args = [1,2];
f(-1, ...args,2,...[3]);
  • 扩展运算符后面还可以放置表达式
const demo = [...(3 > 0 ? ['a'] : [], 'b')];
  • 如果扩展运算符后面是一个空数组,则不产生任何效果
  • 只有函数调用时,扩展运算符才可以放在圆括号里,否则会报错
(...[1,2]); // 报错
console.log((...[1,2])); // 报错
console.log(...[1,2]); // 1 2
  • 替代函数的apply方法

由于扩展运算符可以展开数组,所以不再需要apply方法,将数组转为函数的参数了。

// ES5
function f(x,y,z){
  // ...
}

var args = [0,1,2];
f.apply(null,args);

// ES6
function f(x,y,z){
  // ...
}
let args = [0,1,2];
f(...args);
  • 复制数组

数组是复合的数据类型,直接复制的话,只是复制了指向底层数据结构的指针,而不是克隆一个全新的数组。

const a1 = [1,2]
const a2 = a1;
a2[0] = 2;
console.log(a1); // [2,2]

在***ES5中***

const a1 = [1,2];
const a2 = a1.concat();

a2[0] = 2;
console.log(a1); // [1,2]

在***ES6中使用扩展运算符***

const a1 = [1,2];
// 第一种写法
const a2 = [...a1];
// 第二种写法
const [...a2] = a1;
  • 合并数组
const arr1 = ['a', 'c'];
const arr2 = ['c'];
const arr3 = ['d', 'e'];
// ES5中
arr1.concat(arr2,arr3);
// ES6中
[...arr1, ...arr2, ...arr3];

需要注意的是,上面的这两种都是浅拷贝,如果修改了原来数组的成员,回同步反映到新数组的。

  • 与解构赋值结合
// ES5
a = list[0], rest = list.slice(1);
// ES6
[a, ...rest] = list;

const [first, ...rest] = [1,2,3,4,5];
console.log(first); // 1
console.log(rest); // [2,3,4,5]

注意:如果将扩展运算符用于数组赋值,只能放在参数的最后一位,否则会报错。

  • 字符串

扩展运算符可以将字符串转成正真的数组

console.log([...'hello']); // ["h", "e", "l", "l", "o"]

扩展运算符可以识别正确的双字符的Unicode字符。

'x\uD83D\uDE80y'.length // 4
[...'x\uD83D\uDE80y'].length // 3

凡是设计到操作符四个字节的Unicode字符的函数,会好使用扩展运算符改写

  • 实现Iterator接口的对象

任何定义了遍历器(Iterator)接口的对象,都可以用扩展运算符转为真正的数组。

let nodelist = document.quertSelectorAll('div');
let array = [...nodelist];

方法quertSelectorAll返回一个NodeList对象,由于NodeList对象实现了Iterator所以可以使用扩展运算符将其转化为一个真正的数组。

对于没有Iterator接口的对象,使用扩展运算符将会报错。

Array.from()

方法Array.from()用于将类似数组的对象(array-like object)和可遍历(Iterable)对象(包括ES6新增的数据结构Set和Map)转为真正的数组

let arrayLike = {
  '0': 'a',
  '1': 'b',
  '2': 'c',
  length: 3
}
// ES5
var arr1 = [].slice.call(arrayLike);
// ES6 
var arr2 = Array.from(arrayLike);

只要部署了Iterator接口的数据结构,Array.from都能将其转化为数组

Array.from('hello');  // ['h','e','l','l','o']
let nameSet = new Set(['a','b']);
Array.from(nameSet); // ['a','b']

如果参数是一个真正的数组,Array.from会返回一个一模一样的数组

Array.from([1,2,3]); // [1,2,3]
  • Array.from还可以接受第二个参数,类似于数组的map方法,用来对每一个元素进行处理,将处理后的值放入返回的数组中。
Array.from(arrayLike, x => x * x);
// 等同于
Array.from(arrayLike).map(x => x * x);

Array.of()

方法Array.of()用于将一组值转换为数组

Array.of(1,2,3); // [1,2,3]
Array.of(3).length // 1
方法的主要目的

方法Array.of()主要是弥补数组构造函数Array()的不足。因为参数个数的不同,会导致Array()的行为有差异。

Array(); // []
Array(3); // [, , ,]
Array(1,23,4); // [1,23,4]

方法Array()在没有参数、一个参数、两个参数、三个参数时返回的结果都不一样。只有当参数个数不少于2个时,Array()才会返回由参数组成的新数组。参数只有一个的时候,实际上是在指定数组的长度。

数组实例的copyWithin()

方法copyWithin()在当前数组内部,将指定位置的成员复制到其他位置(会覆盖原有成员),然后返回当前数组。需要注意:使用这个方法会改变当前数组。

Array.prototype.copyWithin(target, start = 0,end = this.length)

这个方法接受三个参数:

  • target(必需):开始替换数据的位置,如果是负数,表示倒数。
  • start(可选):开始读取数据的位置,默认是0,如果是负数表示从末尾开始计算。
  • end(可选):停止读取数据的位置,默认是数组的长度,如果是负数,就从末尾开始计算。

数组实例的find()和findIndex()

方法find()用于找出第一个符合条件的数组元素,参数是一个回调函数,如果没有找到返回undefined.回调函数中接受三个参数:当前值、当前的位置、原数组。

[1,2.3,23,13].find((value,index,arr)=>{
  return value > 9;
})

数组实例的fill()

方法fill()使用给定值填充一个数组

['a','e','d'].fill(7); // [7,7,7]
new Array(3).fill(2); // [2,2,2]

方法fill()用于空数组的初始化非常方便。数组中已经有的元素会被全部抹去。

方法fill()还可以接受第二个第三个参数,用于填充的起始位置和结束位置。

注意:如果填充的类型为对象,那么被赋值的是同一个内存地址的对象,而不是深拷贝对象

数组实例的entries()、keys()和values()

方法entries()keys()values()用于遍历数组。可以使用for...of循环进行遍历,区别是:keys()是对键名的遍历、values()是对键值的遍历,entries()是对键值对的遍历。

  • 如果不使用for...of循环,可以手动调用遍历器对象的next()方法。

数组实例的includes()

方法includes()返回一个boolean值,表示某一个数组是否包含给定的值,与字符串的includes方法类似。ES2016引入该方法

方法includes()的第二个参数表示搜索的开始位置,默认是0,如果是负数,怎么表示倒数的位置。当这个参数的值大于数组长度,就会重置为0开始。

  • Map和Set数据结构有一个has()方法,需要注意和includes区分.
  • Map结构的has()方法用来查找键名的。
  • Set结构的has()方法用来查找值的。

数组实例的flat()和flatMap()

数组的元素有时还是数组,所以方法flat()可以将嵌套的数组元素“拉平”,变成一维数组。这个方法返回一个新的数组,对原数据没有影响。

[1,2,3,[4,5],6].flat(); // [1,2,3,4,5,6]

方法flat()默认只拉平一层,如果需要多层,就可以设置参数。

[1,2,[3,[4,5]],6].flat(2); // [1,2,3,4,5,6]
  • 如果不考虑有几层,都需要转成一维数组的话,可以将这个参数设置为Infinity

  • 如果原数组有空位,flat()方法会跳过这个空位

[1,2,3, ,4].flat(); // [1,2,3,4]

方法flatMap()对原数组元素每个成员执行一个函数,然后执行后的数组执行flat()方法,这个方法也返回一个数组,不改变原数组。

[2,3,4].flatMap((x) => [x,x * 2]); // [2,4,3,6,4,8]
  • 方法flatMap()只能展开一层数组

  • 方法flatMap()的第二个参数用来拌定遍历函数中的this.

数组的空位

数组的空位指的是数组某一个位置没有任何值。

例如:Array构造函数返回的数组都是空位。

Array(2); [ , ,];

注意:空位不是undefined,一个位置的值等于undefined,依然是有值的。空位是没有任何值的,in元算符可以说明这一点。

0 in [undefined,undefined,undefined]; // true
0 in [ , , ,]; // false

在ES5中

  • forEach()filter()reduce()every()some()都会跳过空位
  • map()会跳过空位,但是会保留这个值
  • join()toString()会将这个空位作为undefined处理,而undefinednull会被处理成空字符串。

在ES6中

  • 将空位转为undefined.
  • Array.from()会将数组的空位转成undefined.
  • 扩展运算符(...)也会将空位转为undefined.
  • copyWithin()会将空位一起拷贝
  • fill()会将空位看作正常的数组位置
  • for...of循环也会遍历空位
  • entries()keys()values()find()findIndex()会将空位处理成undefined.

Array.prototype.sort() 的排序稳定性

排序稳定性(stable sorting)是排序算法的重要属性,指排序关键字相同的项目,排序前后的顺序不变。

常见的排序算法中,插入排序、合并排序、冒泡排序等都是稳定的,堆排序、快速排序等都是不稳定的。在***ES2019***规定,Array.prototype.sort()的默认排序算法必须是稳定的。

备注:本文是自己学习阮一峰老师的《ECMAScript 6 入门》所做的笔记,大部分例子来源于此书。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值