Destructuring(解构)

在 ES6 中,另一个强大的功能就是解构。它是一种从存储的数据中提取值的便捷方法(可能是嵌套的)对象和数组。但同时它又有很多的坑,导致某些地方不是很好理解,不过没关系。让我们一点一点剖析它吧。

(一)概述

在接收数据的位置(例如左侧被分配的变量)中,解构允许您使用模式来提取该数据的部分。

例如:

let obj = { first: 'Jane', last: 'Doe' }; 
let { first: f, last: l } = obj; // A

在 A 行中,我们重构 obj:我们通过左侧的模式从中提取数据赋值运算符(=),并将该数据分配给变量 f 和 l。 这些变量是预先自动声明,因为是以 let 开头。

我们将它分解开来,就是如下的形式:

{ first: f, last: l } = { first: 'Jane', last: 'Doe' };
// 也就是说
// f: 'Jane'
// l: 'Doe' 

是不是有些难了?那我们再来看一个数组的例子吧:

let [x,y] = ['a','b'];  // x = 'a'; y = 'b'
// 等同于
let [x] = ['a'];
let [y] = ['b'];

是不是很方便?而且一一对应。当我们预先需要定义大量的变量时,我们就可以使用这样的方式。

另外,我们在 for 循环用也可以使用它。

for (let [x,y] of arr) {...}

for (let {name: n, age: a} of arr) {...}
// 注意:其中 n 和 a 才是变量,'name' 和 'age' 只是变量的名称,目的是为了方便理解变量
// 例如
let n;  // name
// 我们也可以简单的认为上述 for-of 循环中 'name' 是 n 的注释,这样就好理解了吧?

(二)背景:构造数据(对象和数组文本)与提取数据(解构)

要完全理解什么是解构,就要让我们首先检查它的更广泛的上下文。 JavaScript 有此构造数据操作:

let obj = {};
obj.first = 'Jane';
obj.last = 'Doe'; 

它具有提取数据的操作:

let f = obj.first;
let l = obj.last; 

请注意,我们使用的语法与构建时使用的语法相同。
有一个更好的语法来构造 —— 对象字面量:

let obj = { first: 'Jane', last: 'Doe' }; 

ECMAScript 6 中的解构使用相同的语法来提取数据,其中它被称为对象模式:

let { first: f, last: l } = obj; 

(3)解构部分不匹配的情况

我们看一个例子:

let [x] = [];

该表达式将输出什么结果?当然是 undefined 啦。

所以解构值的步骤如下

  1. 如果有匹配的具体值,那么则将它设置为其默认值。
  2. 否则,设置为 undefined。

也就是说:

let [x,y] = ['a'];  // x = 'a'; y = undefined
let {foo: x = 3, bar: y} = {};  // x = 3; y = undefined

注意以下的特殊情况,其值不为 undefined:

let [x = 1] = [undefined];  // x = 1
let {prop: y = 2} = {prop: undefined};  // y = 2

这有个有意思的东西值得注意,默认值只有在它需要时才会被计算:

let [x = 1] = ['a'];
console.log(x);

你觉得以上的输出结果应该为 1 还是 'a' 呢?

没错,聪明!答案就是: **'a' **。为什么呢?这里有个更高级的例子,需要动动脑筋思考下:

let { prop: y = someFunc() } = someValue;

它其实等同于以下的表达式:

let y;
if (someValue.prop === undefined) {
    y = someFunc();
} else {
    y = someValue.prop;
}

如果你将上面的解释步骤看懂了并牢记于心,这部分的内容就没有难度啦!

还有更加有意思的呢!例子如下:

let [x = 3, y = x] = []; // x = 3; y = 3
let [x = 3, y = x] = [7]; // x = 7; y = 7
let [x = 3, y = x] = [7, 2]; // x = 7; y = 2 

也就是说,在解构的时候,你可以在解构的一侧将其设置为默认相等。虽然看起来好像并没有什么用。

以下呢,我再放上几个复杂一些的例子,看懂了它们,那么这一小部分解构的知识点基本也就算掌握啦:

let { prop: x } = {};  // x = undefined
let [{ prop: x } = { prop: 123 }] = [];  // x = 123 
let [{ prop: x } = { prop: 123 }] = [{}];   // x = undefined 
let [{ prop: x = 123 } = {}] = [{}];  // x = 123

是不是并不难呢?我总结了一句话:在解构时,变量与值成一一对应关系,若没有值,则去找变量上的默认值。如果有,则返回该默认值;如果没有默认值,则返回 undefined。

(4)更多的解构示例

以下,我们再将一些更高级的解构。

首先,我们来看一个例子:

let { x, y } = { x: 11, y: 8 }; 

它将输出什么结果呢?没错!是 x = 11; y = 8。那么为什么呢?

其实不难,我们来看一下,它等同于什么:

let { x: x, y: y } = { x: 11, y: 8 }; 

是不是一目了然啦?

我们在这里扩展一个 ES6 中对象写法的知识点,在 ES6 及以后版本,允许我们在对象中简写。示例如下:

// ES5
var obj = {
    a: 'a',
    b: 'b'
}
// 等价于 =>
// ES6
let obj = {
    a,
    b
}

很不是很方便?这样我们就可以少写点内容了。另外,不光是变量如此,方法也是可以简写的。

// ES5
var obj = {
    add: function() {
        // ...
    }
}
// 等价于 =>
// ES6
let obj = {
    add() {
        // ...
    }
}

是不是很爽啊?但是这里有个地方需要注意:ES6 方法的写法可使用于匿名函数中,而具名函数则是不行的。

什么意思?举个例子吧:

let obj = {
    add() {
        // ...
    }
}
// 等价于 =>
let obj = {
    add: function() {
        // ...
    }
}

也就是说,如果你想这个方法(也就是该函数)可以递归自身的话,由于它是匿名的,所以无法调用自身。这种情况下,还是采用 ES5 中的写法吧。


总结

解构我们就暂时讲到这里,其实理解起来并不难,主要是一定要明白它们之间的对应关系是如何的。明天我们讲述——参数处理(Parameter handling )。

你可能感兴趣的:(Destructuring(解构))