ES6 数组解构&变量解构

注:这是一篇学习笔记,记录自己在ES6学习过程中按照自己的思路觉得应该记录的一些要点,方便以后查看和复习。参考:

阮一峰ES6的书籍中变量的解构赋值
我的ES6入门学习规划

ES6引入了解构的方式,可用于变量声明、赋值语句、函数参数定义、for of循环这几个场景,代码简化,值得使用。 前面只提到4个场景,目前未学到其它场景可应用解构。在参考学习的书籍中,扩展运算符应用于对象解构的这个要点,并没有提及,而是在书籍比较靠后的内容才有介绍,在这篇笔记里,我把参考书籍里面跟解构相关的点都总结到这了。

数组解构

将实现了Iterator接口的数据的值,按照位置匹配进行赋值。

  • 只要某种数据具有Iterator接口,就可以采用数组形式的解构,否则报错;
  • null或undefined无法进行数组解构,会报错;
  • string进行数组解构时以字符数组的形式解构;
  • boolean、number进行数组解构时会自动转为对象,默认情况下它们无法进行数组解构;但是Boolean或Number对象实现Iterator接口以后,boolean、number值就能使用数组解构;
  • 允许解构部分包含空位,如 let [,,b] = [1,2,3];
  • 默认值写法:let [a, b=1] = [];
  • 扩展运算符在数组解构中收集数组尚未被解构模式拾取的剩余元素,放到一个新数组,赋给变量;

对象解构

将对象的值,根据模式名称与属性名称相同的原则进行赋值。

  • 解构的模式名称与变量名称相同时,可以只写模式名称;不同时不能简写;
  • 一定要区分清楚解构目标里面哪个是模式,哪个是变量,以及变量名称是否有被省略;
  • null或undefined无法进行对象解构,会报错;
  • string本身可作为对象进行对象解构;
  • number、boolean在对象解构时会自动转为Number、Boolean对象;
  • array 本身可以作为对象进行对象解构;
  • 对象的解构赋值可以取到继承的属性;
  • 解构模式可以使用属性名表达式;
  • 基本上除了null、undefined,其它数据都能进行对象解构;
  • 同时带模式名称、变量名称以及默认值的解构写法:var {x: y = 3} = {};
  • 扩展运算符在对象解构中收集对象自身尚未被解构模式拾取的剩余可枚举属性键(非继承的),合并成为一个新对象,赋给变量。

注意点:
普通的对象解构,可以解构到继承或者不可枚举的属性,扩展运算符的解构,不能解构到继承或不可枚举的属性;
普通的对象解构和扩展运算符的解构,都可以解构到Symbol类型的属性:

1
2
3
4
let a = Symbol();
let b = {[a]: 111};
let {[a]: c} = b;//c 111
let {...d} = b;// d {Symbol(): 111}

共同点

  • 如果解构失败,变量的值就等于undefined

    1
    2
    3
    let [a, b] = [1];
    //a 1
    //b undefined
  • 支持不完全解构,即所有解构变量加起来只能匹配被解构数据的部分值

    1
    let [a, b, c] = [1, 2, 3, 4];
  • 只有解构的值严格等于undefined,默认值才会生效

  • 默认值惰性求值
  • 默认值可以引用解构赋值中已经声明的其它变量

    1
    2
    let [a, b = a] = [1];
    // b 1
  • 都可以使用扩展运算符,且必须是同一个解构模式的最后一个变量;

    1
    2
    3
    4
    let [a, ...b, c] = [1,2,3]; // error
    let [a, [...b], c] = [1, [2, 3], 4]; // success
    let {name, ...left, age} = {name: 'lyzg', age: 28, height: 178}; // error
    let {name, other: {...left}, age} = {name: 'lyzg', age: 28, other: { height: 178}}; // success

特殊点

  • 扩展运算符用于对象解构时,只能接变量,不能再接用于起到嵌套作用的大括号

    1
    let {name, ...{age}} = {name: 'lyzg', age: 28, other: { height: 178}}; // error
  • 扩展运算符用于数组解构,后面还能再接数组解构

    1
    let [a, ...[b,c]] = [1,2,3]; // success

嵌套解构

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
const metadata = {
title: 'Scratchpad',
translations: [
{
locale: 'de',
localization_tags: [],
last_edit: '2014-04-14T08:43:37',
url: '/de/docs/Tools/Scratchpad',
title: 'JavaScript-Umgebung'
}
],
url: '/en-US/docs/Tools/Scratchpad'
};

let {
title: englishTitle, // rename
translations: [
{
title: localeTitle, // rename
},
],
} = metadata;

console.log(englishTitle); // "Scratchpad"
console.log(localeTitle); // "JavaScript-Umgebung"

在嵌套解构中,大括号代表对象解构,中括号代表数组解构;对象解构与数组解构可以混合使用。前面提到的一些解构特性,基本上都是针对同一个解构模式下而言的。

圆括号问题

可以使用圆括号的情况只有一种:赋值语句的非模式部分,可以使用圆括号。

主要用途

  • 交换变量的值;
  • 函数返回多个值,然后用解构轻松拿到每个值;
  • 解析json;
  • 函数参数定义使用解构;
  • 函数参数默认值使用解构;
  • for of循环

    1
    for (var {name: n, family: {father: f}} of people) {/*...*/}
  • 输入模块指定的方法

    1
    let {sin, cos, min, max} = Math;

补充总结

自动看了阮一峰写的书之后,我发现他在总结一些知识点的时,比较喜欢从以下几个维度来思考:

  • 继承属性会如何处理
  • 不可枚举的属性会如何处理
  • symbol类型会如何处理
  • string number boolean null undefined 会如何处理
  • 实现了Iterator接口的数据会如何处理
  • 类数组对象如NodeList arguments对象会如何处理
  • generator函数会如何处理
  • Object会如何处理

毕竟javascript是一门弱类型的语言,所以有一些跟类型相关比较多的技术点,只有将类型使用考虑地更全面,这个知识点才能掌握地越通透。