《深入理解ES6》之解构

解构

解构是一种打破数据结构,将其拆分为更小部分的过程。

ES5及早期版本,从对象和数组中获取特定数据并赋值给变量,实现可能如下。

1
2
3
4
5
6
let opts = {
repeat: true,
save: false
}
let repeat = opts.repeat,
save = opts.save;

这样如果提取更多变量,则需要重复编写类似的代码来为变量赋值。解构简化了获取数据的过程。

对象解构

对象解构的语法形式是在一个赋值操作左边放置一个对象字面量

1
2
3
4
5
6
7
let node = {
type: 'Identifier',
name: 'foo'
};
let { type, name } = node;
console.log(type); //'Identifier'
console.log(name); //'foo'

node.type的值赋值给变量type

使用varletconst解构声明变量,必须要提供等号右侧的值。如var { type, name },则会抛出错误。右侧的值为nullundefined也会报错,因为读取nullundefined的属性都会出发运行错误。

  • 解构赋值
    可以用在变量赋值时使用解构语法,如在定义变量后,修改他们的值。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    let node = {
    type: 'Identifier',
    name: 'foo'
    },
    type = 'Literal',
    name = 5;
    ({ type, name } = node);
    console.log(type); //'Identifier'
    console.log(name); //'foo'

一定要用括号包裹结构赋值语句,JavaScript引擎将一对开放的大括号视为一个代码块,代码块不允许出现在赋值语句的左侧,添加小括号其转化为一个表达式。

  • 默认值
    使用解构赋值表达式时,如果指定的变量名称在对象中不存在,那么这个变量会被赋值为undefined
    1
    2
    3
    4
    5
    6
    let node = {
    type: 'Identifier',
    name: 'foo'
    };
    let { type, name, value } = node;
    console.log(value); //undefined

当指定属性不存在的时候,可以定义一个默认值,和函数默认参数一样。

1
2
3
4
5
6
let node = {
type: 'Identifier',
name: 'foo'
};
let { type, name, value=true } = node;
console.log(value); //true

  • 为非同名变量赋值
    上面解构赋值使用的都是与对象属性同名的变量,如node.type的值赋值给了变量type,可以使用不同命名的变量。
    1
    2
    3
    4
    5
    6
    7
    let node = {
    type: 'Identifier',
    name: 'foo'
    };
    let { type: localType, name: localName } = node;
    console.log(localType); //'Identifier'
    console.log(localName); //'foo'

这种语法与原来的对象字面量的语法相悖,这里是名称在冒号右边。使用其他变量名进行赋值时,也可以添加默认值,在变量名后添加等号和默认值即可。

1
let { type: localType, name: localName='bar' } = node;

  • 嵌套对象解构
    解构嵌套对象与对象字面量类似,可以将更深层级对象拆解以获取想要的值。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    let node = {
    type: 'Identifier',
    name: 'foo',
    loc: {
    start: {
    line: 1,
    column: 1
    },
    end: {
    line: 1,
    column: 4
    }
    }
    }
    let { loc: { start } } = node;
    console.log(start); //{ line: 1, column: 1 }

嵌套对象解构中,冒号前的标识符都代表在对象中的检索位置,右侧为被赋值的变量名。如果冒号后是花括号,则意味着获取的值在更深的层级中。同样也可以使用与对象属性名不同的变量名。

数组解构

使用数组字面量且解构操作全部在数组内完成。通过值在数组中的位置进行选取,且可以将其存储在任意变量中。这个过程中,不影响数组本身。

1
2
3
4
let colors = ['red', 'green', 'blue'];
let [firstColor, secondColor] = colors;
console.log(firstColor); //'red'
console.log(secondColor); //'green'

在解构模式中,也可以只提取制定数组中的值,使用逗号做为占位符,想要获取数组某个位置的值,指定变量名,其他用逗号占位即可。

1
2
3
let colors = ['red', 'green', 'blue'];
let [,, thirdColor] = colors;
console.log(thirdColor); //'blue'

  • 解构赋值
    在变量赋值也是可以使用数组解构,但是不需要使用小括号。
    1
    2
    3
    4
    5
    6
    7
    let colors = ['red', 'green', 'blue'],
    firstColor = 'black',
    secondColor = 'purple';
    [firstColor, secondColor] = colors;
    console.log(firstColor); //'red'
    console.log(secondColor); //'green'

数组解构中,有个独特的用例:交换两个变量的值。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//ES5中交换两个变量,需要引入第三个临时变量
// let a = 1,
// b = 2,
// tmp;
// tmp = a;
// a = b;
// b = tmp;
//ES6中
let a = 1,
b = 2;
[a, b] = [b, a];
console.log(a); //2
console.log(b); //1

赋值语句左侧事一个解构模式,右侧是一个为交换过程创建的临时数组字面量。代码执行过程,将临时数组解构,把ba的值复制到左侧数组的前两个位置,最终变量交换了它们的值。

同对象解构赋值一样,右侧表达式的值不能为nullundefined

  • 默认值
    可以在数组解构赋值表达式中为数组中的任意位置添加默认值,当指定位置的的值不存在或者其值为undefined时,使用默认值。

    1
    2
    3
    4
    let colors = ['red'];
    let [firstColor, secondColor='blue'] = colors;
    console.log(firstColor); //'red'
    console.log(secondColor); //'blue'
  • 嵌套数组解构
    嵌套数组解构和嵌套对象解构类似,在原有的解构模式中,插入另一个解构模式。

    1
    2
    3
    4
    5
    let colors = ['red', ['green', 'lighitgreen'], 'blue'];
    let [firstColor, [secondColor]] = colors;
    console.log(firstColor); //'red'
    console.log(secondColor); //'green'
  • 不定元素
    在数组解构中,可以通过...语法将数组中的其余元素赋值给一个特定的变量。

    1
    2
    3
    4
    5
    6
    let colors = ['red', 'green', 'blue'];
    let [firstColor, ...restColors] = colors;
    console.log(firstColor); //'red'
    console.log(restColors); //[ 'green', 'blue' ]

还可以通过不定元素的语法实现复制一个数组的功能。

1
2
3
4
5
6
var colors = ['red', 'green', 'blue'];
// ES5
// var cloneColors = colors.concat();
let [...cloneColors] = colors;
console.log(cloneColors); //[ 'red', 'green', 'blue' ]

混合解构

可以混合使用对象解构和数组解构来创建更多复杂的表达式。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
let node = {
type: 'Identifier',
name: 'foo',
loc: {
start: {
line: 1,
column: 1
},
end: {
line: 1,
column: 4
}
},
range: [0, 3]
}
let {
loc: { start },
range: [startIndex]
} = node;
console.log(start.line); //1
console.log(start.column); //1
console.log(startIndex); //0

解构模式中的locrange仅代表它们在node对象中所处的位置。