4

含义

扩展操作符(...)可在函数调用/数组构造时, 将数组表达式或者string在语法层面展开; 还在构造对象时, 将对象表达式按key-value的方式展开;

扩展运算符的应用

1.复制数组

复制又分为深复制和浅复制。

  • 浅复制:复制数组的内存地址
  • 深复制:复制数组中的元素内容(数据)
    数组是复合的数据类型,直接复制的话,只是复制了指向底层数据结构的指针,而不是克隆一个全新的数组。

    //浅复制
    const a1 = [1, 2];
    const a2 = a1;
    a2[0] = 2;
    a1 // [2, 2]

    在上面的代码中a2并不是a1的克隆,而是指向同一份数据的另一个指针。修改a2,会直接导致a1的变化。

//深复制
const a1 = [1, 2];
// 写法一
const a2 = [...a1];
// 写法二
const [...a2] = a1;
a2[0] = 2;
a1 // [1, 2]
a2 // [2, 2]

从上面的结果可以看出,a2都是克隆a1的。

2.合并数组

const a1 = ['a', 'b'];
const a2 = ['c'];

const a3 = [...a1, ...a2];
console.log(a3); // ['a', 'b', 'c']
a3[0] = 0;
console.log(a1,a2,a3);//['a', 'b'] ['c'] [0, 'b', 'c']

a1和a2,实现了数组的复制和合并,得到了一个新的数组a3

3.与解构赋值结合

const [a1, ...a2] = [1, 2, 3, 4, 5];
a1 // 1
a2  // [2, 3, 4, 5]
//解释:a1 是数组中的第一个元素所以是1,
//...a2 使用了剩余参数语法,所有a2的值为[2, 3, 4, 5]

const [a1, ...a2] = [];
a1 // undefined
a2  // []
//因为是一个空数组,所以a1为undefined,a2位空数组


const [a1, ...a2] = ["foo"];
a1  // "foo"
a2   // []
//只有一个元素 ,所以ai: foo, 因为后面没有了所以a2为空数组

//如果使用了剩余参数语法,则必须放后面,否则会出出现报错
const [...a1, a2] = [1, 2, 3, 4, 5];
//报错:Uncaught SyntaxError: Rest element must be last element

4.字符串

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

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

上面的写法,有一个重要的好处,那就是能够正确识别四个字节的 Unicode 字符。

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

上面代码的第一种写法,JavaScript 的字符串长度计算是基于 UTF-16 编码的单元的数量,而不是直接基于 Unicode 字符的数量。UTF-16 编码是一种可变长度的编码方式,它使用 16 位的编码单元(代码单元)来表示字符。
这是因为一些字符需要使用两个 16 位的编码单元比如 emoji 表情和一些汉字,例如表情 '🚀',它的 Unicode 码点是 U+1F680。在 UTF-16 中,这个字符被编码为两个 16 位的编码单元:'\uD83D\uDE80',这这里的长度是2。最后x,y加起来就是4。
使用扩展运算符([...'x\uD83D\uDE80y']) 时,它创建一个数组,其中的每个元素对应字符串中的一个字符,不论它是一个 16 位代码单元字符还是代理对的一部分。因此,结果数组的长度为 3

5.Map 和 Set 结构...对象转换成数组

扩展运算符内部调用的是数据结构的 Iterator 接口,因此只要具有 Iterator 接口的对象,都可以使用扩展运算符,比如 Map 结构。

let map = new Map([
  [1, 'one'],
  [2, 'two'],
  [3, 'three'],
]);

let arr = [...map.keys()]; //[1,2,3]

总结

可以看出,展开运算符(...)可用于合并数组、克隆数组或对象、传递可变数量参数,以简化代码。


zZ_jie
396 声望8 粉丝

虚心接受问题,砥砺前行。