ES6 解构赋值

解构赋值

  • 定义
    ES6按照一定模式从数组或者对象中获取值称为解构赋值。
  • 数组解构赋值
let [a1, a2, a3] = [1, 2, 4];
let [b1, [b2, b3], b4] = [1, [3, 4], 5];
let [c1, c2] = [1, ];
console.log(a1, a2, a3); // 1,2,4
console.log(b1, b2, b3, b4); // 1,3,4,5
console.log(c1, c2); // 1,undefined 

也可指定默认值

let [foo = true] = [];
foo // true 

只有当一个变量对应的值,严格等于(===)undefined时才会赋给变量默认值

如下:

let [x = 1] = [undefined];
x // 1

let [x = 1] = [null];
x // null 

如果默认值是表达式,则这个表达式是惰性求解的,即只有当值为undefined,这个表达式才会进行求解

function f() {
 console.log('aaa');
}

let [x = f()] = [1];
x // 1 
function f() {
 console.log('aaa');
}

let [x = f()] = []; // aaa 
  • 对象解构赋值

对象解构赋值是按属性名进行匹配的,所以顺序无关

let { bar, foo } = { foo: "aaa", bar: "bbb" };
foo // "aaa"
bar // "bbb" 

如果变量名和属性名不一致,可以使用如下方式赋值,这样的赋值属性名是取不到值的:

let { foo: baz } = { foo: "aaa", bar: "bbb" };
baz // "aaa"
foo // error: foo is not defined 

如果我们使用let声明变量,然后进行解构赋值

// 报错
let foo;
{foo} = {foo:1}; 

因为js引擎会将{}中的代码理解成代码块,所以出现=赋值号会出现错误,需要用()包裹起来,让js引擎将其识别为表达式

let foo;
({foo} = {foo:1}); 

而且数组可以看做特殊的数组,所以也可以用对象解构进行赋值

let arr = [1, 2, 3];
let {0 : first, [arr.length - 1] : last} = arr;
first // 1
last // 3 
  • 字符串/数值/布尔值解构赋值
const [a, b, c, d, e] = 'hello';
a // "h"
b // "e"
c // "l"
d // "l"
e // "o" 

字符串/数字/布尔值的包装对象有很多方法,可以通过解构赋值获取方法

let {toString: s} = 123;
s === Number.prototype.toString // true

let {toString: s} = true;
s === Boolean.prototype.toString // true 
  • 函数参数解构赋值
function add([x, y]){
 return x + y;
}

add([1, 2]); // 3 

也可以使用默认值

第一种

function move({x = 0, y = 0} = {}) {
 return [x, y];
}

move({x: 3, y: 8}); // [3, 8]
move({x: 3}); // [3, 0]
move({}); // [0, 0]
move(); // [0, 0] 

第二种

function move({x, y} = { x: 0, y: 0 }) {
 return [x, y];
}

move({x: 3, y: 8}); // [3, 8]
move({x: 3}); // [3, undefined]
move({}); // [undefined, undefined]
move(); // [0, 0] 

第一种是分别对x,y分别进行赋值,第二种则是对整个函数参数进行赋值,所以只有不传参数,才会赋默认值

  • 圆括号问题
  1. 不能使用圆括号的情况
  • 变量声明语句中,不能带圆括号
let [(c)] = [1]; //报错
let {x:(c)} = {x:1}; // 报错 
  • 函数参数,模式不能带圆括号
    这很好理解,因为函数参数其实也是会声明变量的
  1. 可以使用圆括号的情况
    赋值语句的非模式部分(不能对js引擎的模式匹配产生影响)
[(b)] = [3]; // 正确
({ p: (d) } = {}); // 正确
[(parseInt.prop)] = [3]; // 正确 
  • 圆括号使用的原则
  1. 不能对js引擎的模式识别产生影响
  2. 不能对表达式进行赋值
  3. 不能在解构赋值声明中使用圆括号
  • 用途
  1. 交换变量值
let x = 1;
let y = 2;

[x, y] = [y, x]; 

这是由于x,y被赋值到一个数组中,然后进行分别赋值

  1. 遍历Map结构
var map = new Map();
map.set('first', 'hello');
map.set('second', 'world');

for (let [key, value] of map) {
 console.log(key + " is " + value);
} 

只有部署有iterator借口的对象进行for...of..的遍历

  1. 返回值是对象
    可以提取对象中的属性到各个变量中
// 返回一个数组

function example() {
 return [1, 2, 3];
}
let [a, b, c] = example();

// 返回一个对象

function example() {
 return {
   foo: 1,
   bar: 2
 };
}
let { foo, bar } = example(); 

模块方法提取

const { SourceMapConsumer, SourceNode } = require("source-map"); 
  1. 无序的函数参数
// 参数是一组无次序的值
function f({x, y, z}) { ... }
f({z: 3, y: 2, x: 1}); 
  1. 函数参数默认值
function f(a, b) {
 a = a||0;
 b = b||0;
 return a+b;
}

console.log((1)); // 1 

转换为

function f(a=0, b=0) {
 return a+b;
}

console.log((1)); // 1