ECMAScript 6之数组的扩展

ECMAScript 6之数组的扩展

1. 扩展运算符

扩展运算符(...),将一个数组转为用逗号分隔的参数序列。扩展运算符背后是调用的遍历器接口,只要部署了遍历器接口的对象,都能使用扩展运算符。

let x = [1, 2, 3, 4, 5, 6];
console.info(...x); // 1 2 3 4 5 6

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

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

let a = [1, 2];
add(...a); // 3

如果扩展运算符后面跟一个空数组,不会有任何效果。

console.info(...[], 1); // 1

扩展运算符后面可以是表达式。

function f(x) {
	if (x > 0) {
		return [1, 2, 3, 4];
	}else {
		return  [-1, -2, -3, -4];
	}
}

console.info(...f(1)); // 1 2 3 4
console.info(...f(-1)); // -1 -2 -3 -4

扩展运算符不能放在括号里面,除非是函数调用。

// 扩展运算符只能放在函数调用的括号里面
console.info(...[1, 2, 3]); // 1 2 3

console.info((...[1, 2, 3])); // Uncaught SyntaxError: Unexpected token '...'
(...[1, 2, 3]); // Uncaught SyntaxError: Unexpected token '...'

1.1 扩展运算符的应用

(1).替代函数的apply方法。apply方法经常被用来将数组转为函数的参数,而有了扩展运算符,可以完全替代apply方法。

let x = [23, 34, 56];

// ES5写法
Math.max.apply(null, x); // 56x

// ES6写法
Math.max(...x); // 56

(2).复制数组。直接将数组赋值给另一个数组,其中一个数组的数据发生变化,另一个会跟着变化。

const a1 = [1, 2];
const a2 = a1;

a2; // [1, 2]

// 改变a1数据,a2数据跟着改变
a1[1] = 4;
a2; // [1, 4]

// 改变a2数据,a1数据跟着改变
a2[0] = 5;
a1; // [5, 4]

通过扩展运算符可以获得数组的一个克隆,从而避免上述情况。

const a1 = [1, 2];

// ES5写法
const a2 = a1.concat();

// ES6 写法
const a2 = [...a1];

(3).合并数组。扩展运算符提供了新的写法。

const a1 = [1, 2, 3];
const a2 = [4, 5, 6];
const a3 = [7, 8, 9];

// ES5写法
let a4 = a1.concat(a2, a3);
a4; // [1, 2, 3, 4, 5, 6, 7, 8, 9]

//ES6写法
let a5 = [...a1, ...a2, ...a3];
a5; //  [1, 2, 3, 4, 5, 6, 7, 8, 9]

上述代码中,不管是ES5写法还是ES6写法,获得的新数组都是浅拷贝,即新数组的成员是对原数组成员的引用,修改了引用指向的值,会同步到新数组。

(4).与解构赋值结合。扩展运算符可以与解构赋值结合,用于生成数组。

const [first, ...rest] = [1, 2, 3, 4, 5];
first; // 1
rest;  // [2, 3, 4, 5]

const [first, ...rest] = ["foo"];
first  // "foo"
rest   // []

扩展运算符用于数组赋值,只能放在数组的最后一位,否则会报错。

const [ ...rest, first] = [1, 2, 3, 4, 5]; // Uncaught SyntaxError: Rest element must be last element

(5).字符串。扩展运算符可以将字符串转换为真正的数组,而且还能正确识别四个字节的Unicode字符。

[..."jidi"]; // ["j", "i", "d", "i"]

// 能正确识别四个字节的字符 
[...String.fromCodePoint(134072)].length; // 1

可以使用扩展运算符正确获得字符串的长度,不用关注字符串是几个字节。

function getStringLegth(s) {
	return [...s].length;
}

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

// 返回所有script节点
let scripts = document.scripts;

[...scripts]; //  [script, script, script, script, script, script, script, script]

2. Array.from()

Array.from方法用于将类似数组的对象和可遍历的对象转换为真正的数组。

// 类似数组的对象
let b = {
    0: "jidi",
    1: "xuxiake",
    length: 2
}
Array.form(b); //  ["jidi", "xuxiake"]

// 可遍历的对象
let a = new String ("jidi");
Array.from(a); // ["j", "i", "d", "i"]

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

Array.from([1, 2, 3]); //  [1, 2, 3]

Array.from还可以接受第二个参数,用来对每个元素进行处理,将处理后的值放入返回的数组,可以参考数组的map方法。

// 数组中的每个值+1
Array.from([1, 2, 3, 4], x => x + 1); // [2, 3, 4, 5]

3. Array.of

Array.of方法用于将一组值,转换为数组。

Array.of("jidi", 2, 3); // ["jidi", 2, 3]
Array.of(12); // [12]
Array.of(); // []

Array()构造函数有一个很大的缺陷,就是不同的参数,会导致它的行为不一致。Array.of方法主要是为了弥补数组构造函数Array()的不足。

// 无参数时,返回一个空数组
new Array(); // []

// 单个正整数参数,表示返回的新数组的长度
new Array(1); // [ empty ]
new Array(2); // [ empty x 2 

// 多参数时,所有参数都是返回的新数组的成员
new Array(1, 2) // [1, 2]

4. Array.prototype.find()和Array.prototype.findIndex()

Array.prototype.find()用于找出符合条件的第一个数组成员。参数是一个回调函数,数组成员依次执行回调函数,直到找到第一个返回true的成员,然后会返回改成员。如果没找到,返回undefined

// 找到数组中的第一个偶数
[1, 2, 3, 4, 5].find( x => x % 2 === 0); // 2
// 没找到,返回undefined 
[1, 3, 7].find( x => x % 2 === 0); // undefined

Array.prototype.find()方法的回调函数可以接受三个参数:依次为当前的值、当前的位置和原数组。

[1, 2, 3].find((value, index, array) => value === index + 1); // 1

Array.prototype.find()方法可以接受第二个参数,用来绑定回调函数的this对象。

// 定义回调函数,找出年龄比this所指向的对象年龄大的数组成员
function f(x) {
	if (this.age < x.age) {
		return true;
	}
}

let rycony = {name: "rycony", age: 22};

[{name: "jidi", age: 22}, {name: "xuxiake", age: 23}].find(f, rycony ); // {name: "xuxiake", age: 23}

Array.prototype.findIndex()用法参照Array.prototype.find(),只是它返回的是第一个符合条件的数组成员的下标位置,如果没找到返回-1

5. Array.prototype.fill()

Array.prototype.fill()使用给定值,填充一个数组。

["jidi", "xuxiake", "rycony"].fill("*"); //  ["*", "*", "*"]

Array.prototype.fill()可以接受第二个和第三个参数,用于指定填充的起始位置和结束位置。

// 使用指定值填充指定起始位置的数组元素
["jidi", "xuxiake", "rycony"].fill("*",1, 2); //   ["jidi", "*", "rycony"]

6. Array.prototype.entries(),Array.prototype.keys() 和 Array.prototype.values()

Array.prototype.entries()Array.prototype.keys()Array.prototype.values()用于遍历数组。它们都返回一个遍历器对象,可以用for...of循环进行遍历,唯一的区别是keys()是对键名的遍历、values()是对键值的遍历,entries()是对键值对的遍历。

// 遍历键名
for (let key of ['a', 'b'].keys()) {
  console.log(key);
}
// 0   1

// 遍历键值
for (let value of ['a', 'b'].values()) {
  console.log(value);
}
// “a”   “b”

// 遍历键值对
for (let [key, value] of ['a', 'b'].entries()) {
  console.log(key, value);
}
// 0 "a"   1 "b"

7. Array.prototype.includes

Array.prototype.includes方法返回一个布尔值,表示某个数组是否包含给定的值。

["jidi", "xuxiake", "rycony"].includes("jidi"); // true

Array.prototype.includes方法可以接受第二个参数,表示搜索的起始位置,默认为0。如果为负数,表示倒数的位置,如果参数值大于数组长度,会重置为0

["jidi", "xuxiake", "rycony"].includes("jidi", 1); // false

//为负数,表示倒数的位置,从-1开始计数
["jidi", "xuxiake", "rycony"].includes("jidi", -2); // false

8. Array.prototype.flat(),Array.prototype.flatMap()

Array.prototype.flat()用于将嵌套的数组变成一维的数组。该方法返回一个新数组。

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

Array.prototype.flat()默认只会“拉平”一层,如果想要“拉平”多层的嵌套数组,可以将flat()方法的参数写成一个整数,表示想要拉平的层数,默认为1

// 默认拉平一层
[1, 2, [3, [4, 5]]].flat(); // [1, 2, 3, Array(2)]

// 拉平两层
[1, 2, [3, [4, 5]]].flat(2); // [1, 2, 3, 4, 5]

如果不管有多少层嵌套,都要转成一维数组,可以用Infinity关键字作为参数。

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

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

// 会忽略数组中空位元素
[, , 1, 2, , 4, 5].flat(); // [1, 2, 4, 5]

Array.prototype.flatMap()方法会对每个数组成员执行一个函数,然后对返回值组成的数组执行flat()方法。该方法返回一个新数组,不会改变原数组。

// 相当于先调用数组map方法,然后对执行了map方法的结果组成的数组执行flat方法
[2, 3, 4, 5, 6].flatMap(x => [x, x + 1]); // [2, 3, 3, 4, 4, 5, 5, 6, 6, 7]

// flatMap方法只能展开一层数组
[2, 3, 4, [5, 6]].flatMap(x => [x, x + 1]); // [2, 3, 3, 4, 4, 5, Array(2), "5,61"]

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

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

10. 参考链接

本篇博文是我自己学习笔记,原文请参考:ECMAScript 6 入门
如有问题,请及时指出!
欢迎沟通交流,邮箱:jidi_jidi@163.com

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值