JavaScript语言教程

Javascript ES6的解构

  数组是Javascript有关集合列表的表达方式,列表集合如此重要,是因为它是代表事物有顺序的集合,一个顺序集合是对现实世界的基本抽象方式。

数组的语法如下:

[1]
//=> [1]

[2, 3, 4]
//=> [2,3,4]

表达式也可以在数组中使用:

[ 2, 3, 2 + 2 ]
//=> [2,3,4]

下面看看使用Javascript ES6的数组字面量Array literal(又翻译为字面量、字面常量)的表达式:

const wrap = (something) => [something];

wrap("lunch")
//=> ["lunch"]

数组字面量Array literal是一个表达式,而数组是一个引用类型,每次数组字面量被调用时都会计算赋值,我们总是得到一个新的不同的数组,尽管这些数组包含同样的数组元素。

[] === []
//=> false

[2 + 2] === [2 + 2]
//=> false

const array_of_one = () => [1];

array_of_one() === array_of_one()
//=> false

下面看看如何分解数组,也就是通过函数进行数组结构分解,Destructuring解构是Common Lisp中的一个特性,我们可以使用“[,表达式,]”构造construct一个数组字面量,下面是一个使用名称的数组字面量:

const wrap = (something) => [something];

我们使用代码块和外部名称扩展一下它:

const wrap = (something) => {

  const wrapped = [something];

 

  return wrapped;

}

 

wrap("package")

  //=> ["package"]

 

上面代码中const wrapped = [something]; 这一句(第二行)非常有意思,左边是要绑定的名称,右边是数组字面量,也就是一种构造数组的模板,这非常像quasi-literal字符串。

在JS中我们可以反转语句,将模板放在左边,值放在右边:

const unwrap = (wrapped) => {

  const [something] = wrapped;

 

  return something;

}

 

unwrap(["present"])

  //=> "present"

注意第二行语句const [something] = wrapped;解构了wrapped代表的数组,将分解后的值绑定到一个只有单个数组元素的something,这里只是分解出一个元素,我们还可以分解出多个元素:

const surname = (name) => {

  const [first, last] = name;

 

  return last;

}

 

surname(["Zhang", "San"])

  //=> "San"

上述代码分解出姓first和名last,最后该函数返回的是的名last的值。虽然这种效果可以使用:

(name) => name[1]

这种普通方式来分解获取,但是解构是一种重新组装使用数据的代码风格,一种valuable代码风格。

解构可以嵌套:

const description = (nameAndOccupation) => {

  const [[first, last], occupation] = nameAndOccupation;

 

  return `${first} is a ${occupation}`;

}

 

description([["Zhang", "San"], "programmer"])

  //=> "Zhang is a programmer"

 

收集gathering

  有时我们需要从一个数组中取出中另外一个数组,比如下面代码是从数组中排除头部,然后收集除了头部以外的元素:

const [car, ...cdr] = [1, 2, 3, 4, 5];

 

car

  //=> 1

cdr

  //=> [2, 3, 4, 5]

这里使用了“...”来表达收集,但是它不能提供通用的模式匹配能力,比如,我们不能这样写:

const [...butLast, last] = [1, 2, 3, 4, 5];
//=> ERROR

const [first, ..., last] = [1, 2, 3, 4, 5];
//=> ERROR

在构造器中“...”可以在前面,比如:

const date = new Date(...[2015, 1, 1]);

请注意当我们引入了解构destructuring时,这其实是一种数组字面量的顺序问题,如果:

const wrapped = [something];

那么:

const [unwrapped] = something;

现在问题来了,上面展示了解构的反转方式,那么什么是收集gathering的反转呢?

比如前面案例:

const [car, ...cdr] = [1, 2, 3, 4, 5];

它的反转是:

const cons = [car, ...cdr];

看看下面代码:

const oneTwoThree = ["one", "two", "three"];

["zero", ...oneTwoThree]
//=> ["zero","one","two","three"]

这段代码可以运行,将一个数组的元素放入另外一个数组,使用“...”解构是“收集gathering”,而在字面量literal中将元素插入称为“扩展spreading”

 

解构参数

  考虑下面场景,我们传入参数:

foo()
bar("smaug")
baz(1, 2, 3)

这非常类似数组字面量,再看看将值绑定到参数名称:

const foo = () => ...
const bar = (name) => ...
const baz = (a, b, c) => ...

这非常类似解构,但是有一点区别,我们并不试图收集什么,比如:

const numbers = (...nums) => nums;

numbers(1, 2, 3, 4, 5)
//=> [1,2,3,4,5]

const headAndTail = (head, ...tail) => [head, tail];

headAndTail(1, 2, 3, 4, 5)
//=> [1,[2,3,4,5]]

学习Javascript ES6几个重要特性