destructuring assignment

Javascript的解构分配语法通过映射数组或字面量对象的语法来提取从数组或对象里提取数据.

语法

[a, b] = [1, 2]
[a, b, ...rest] = [1, 2, 3, 4, 5]
{a, b} = {a:1, b:2}
{a, b, ...rest} = {a:1, b:2, c:3, d:4}  //ES7

{a, b} = {a:1, b:2} 这个语法是不能独立使用的,因为左边的 {a,b} 会被认为是一个代码块,而不是一个字面量对象.
但是,({a, b} = {a:1, b:2}) 格式是可以的,它和 var {a, b} = {a:1, b"2} 一致.

描述

对象和数组字面量表达式为创建临时数据包提供了一种简单的方法. 一旦成功创建了数据包,你可以随心所欲的使用它.你甚至可以把它放在函数的返回值里.

使用解构分配有一个特别实用的功能: 你只需要通过一句代码就可以读取整个数据解构,可以用它做很多事情.下面会给出例子.

这个特点某些其他语言也有,比如 Perl 和 Python.

数据解构

简单的例子

var foo = ["one", "two", "three"];

// without destructuring
var one   = foo[0];
var two   = foo[1];
var three = foo[2];

// with destructuring
var [one, two, three] = foo;

免声明分配

在使用解构分配的时候,不一定要声明变量.

var a, b;

[a, b] = [1, 2];

变量交换

执行这段代码以后,b等于1,a等于3. 在没有解构分配功能之前,要实现这个操作需要一个临时变量

var a = 1;
var b = 3;

[a, b] = [b, a];

多变量返回值

多亏于解构分配,函数可以返回多个变量了.虽然它一直都可以返回一个数组,但是解构分配赋予了它更多使用灵活性.

function f() {
  return [1, 2];
}

可以看到,函数返回了一个像数组一样的东西,把所有的值都放在’[]’里.你可以使用这种方式返回任何数量的数据.在这个栗子里, f() 返回 [1,2] 作为输出.

var a, b;
[a, b] = f();
console.log("A is " + a + " B is " + b);

[a,b] = f() 这句代码会把函数返回的结果依次分配给’[]’里的变量: a被设置为1,b被设置为2.你也可以像以前一样把返回值当做数组用.

var a = f();
console.log("A is " + a);

在这个栗子里,a 是一个包含了1和2的数组.

忽略某些返回值

你还可以忽略某些你不需要的值:

function f() {
  return [1, 2, 3];
}

var [a, , b] = f();
console.log("A is " + a + " B is " + b);

执行这段代码以后, a等于1,b等于3. 2这个值就被忽略了.你可以使用这种方式来忽略一个或多个(甚至全部)返回值.举个栗子:

[,,] = f();

从正则表达式的匹配结果来拉取数据

当正则表达式通过 exec() 方法去匹配的时候,它会返回一个数组,数组的第一个值是整个被进行匹配的字符串,后面的值分别是匹配各个’()’里的内容得到的结果.解构分配能让你轻易地获取到数组里的各个部分内容,如果你不需要整个字符串,可以忽略它.

var url = "https://developer.mozilla.org/en-US/Web/JavaScript";

var parsedURL = /^(\w+)\:\/\/([^\/]+)\/(.*)$/.exec(url);
var [, protocol, fullhost, fullpath] = parsedURL;

console.log(protocol); // logs "https"

对象解构

简单的例子

var o = {p: 42, q: true};
var {p, q} = o;

console.log(p); // 42
console.log(q); // true 

// 分配新的变量名
var {p: foo, q: bar} = o;

console.log(foo); // 42
console.log(bar); // true 

免声明分配

同样,在使用解构分配对象的时候,也不一定要声明.

var a, b;

({a, b} = {a:1, b:2});

在使用免声明对象字面量解构分配时,包围语句的’( .. )’必须要有.

定义函数参数默认值

ES5版本

function drawES5Chart(options) {
  options = options === undefined ? {} : options;
  var size = options.size === undefined ? 'big' : options.size;
  var cords = options.cords === undefined ? { x: 0, y: 0 } : options.cords;
  var radius = options.radius === undefined ? 25 : options.radius;
  console.log(size, cords, radius);
  // now finally do some chart drawing
}

drawES5Chart({
  cords: { x: 18, y: 30 },
  radius: 30
});

ES6版本

function drawES6Chart({size: size = 'big', cords: cords = { x: 0, y: 0 }, radius: radius = 25} = {}) 
{
  console.log(size, cords, radius);
  // do some chart drawing
}

drawES6Chart({
  cords: { x: 18, y: 30 },
  radius: 30
});

在火狐里,解构分配的默认值功能还没有被支持: var { x = 3 } = {} 以及 var [foo = "bar"] = [].查看关于函数参数解构分配默认值问题的bug: bug 932080;

模块化加载(非ES6方法)

解构分配可以加载指定的非ES6子组件,比如这里,使用插件SDK

const { Loader, main } = require('toolkit/loader');

嵌套对象和数组的解构分配

var 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"
};

var { title: englishTitle, translations: [{ title: localeTitle }] } = metadata;

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

for循环里的解构分配

var people = [
    {
     name: "Mike Smith",
     family: {
       mother: "Jane Smith",
       father: "Harry Smith",
       sister: "Samantha Smith"
     },
     age: 35
    },
    {
     name: "Tom Jones",
     family: {
       mother: "Norah Jones",
       father: "Richard Jones",
       brother: "Howard Jones"
     },
     age: 25
    }
];

for (var {name: n, family: { father: f } } of people) {
    console.log("Name: " + n + ", Father: " + f);
}

// "Name: Mike Smith, Father: Harry Smith"
// "Name: Tom Jones, Father: Richard Jones"

从函数参数对象里获取对应属性值

function userId({id}) {
  return id;
}

function whois({displayName: displayName, fullName: {firstName: name}}){
  console.log(displayName + " is " + name);
}

var user = { 
  id: 42, 
  displayName: "jdoe",
  fullName: { 
      firstName: "John",
      lastName: "Doe"
  }
};

console.log("userId: " + userId(user)); // "userId: 42"
whois(user); // "jdoe is John"

这样可以获取对象里的 id,displayName,firstName 属性,然后打印出来.

计算后的属性名和解构分配

和字面量对象一样,计算后的属性名也可以用于结构分配(就是下标型的属性名)

let key = "z";
let { [key]: foo } = { z: "bar" };

console.log(foo); // "bar"

原文地址