ES6非常棒的特性-解构

好的代码实践

我们有一个方法:buildAnimal(),它需要三个参数:accessory, animal, color。

function buildAnimal(accessory, animal, color){...}

然后我们需要加一个参数,我们需要怎么做?很简单啊,直接在方法名后面加不就好了吗。

但是我们是好的程序员,怎么能这么没追求啊是不是:

“Functions should have a small number of arguments. No argument is best, followed by one, two, and three. More than three is very questionable and should be avoided with prejudice.”
Robert C. Martin’s Clean Code

我们开始重构,把所有的参数放到一个对象里面:animalData,它有下面三个属性:animal, color, hairType

function buildAnimal(animalData){...}

如果要加参数,直接加到animalData的属性里面就好了。
但是,又有一个问题了。如果我们要冲对象里面拿数据:可能要这样:

function buildAnimal(animalData){
    let accessory = animalData.accessory,
        animal = animalData.animal,
        color = animalData.color,
        hairType = animalData.hairType;
    ...
}

代码重复了很多,很不优雅对不对!

解构

先定义一个对象:

let obj = {
    accessory: 'horn',
    animal: 'horse',
    color: 'purple',
    hairType:'curly'
}

解构的原理是:从一个对象一次性解析出多个属性给不同变量,比如数组中解析出元素,从map/set中解析出数据等。

模式

任何解构都有两个部分
1 解构源: 等号右边是要解构的对象。
2 解构目标:等号左边是要解构的对象。

对象解构(解构源)

上面的例子,解构的写法可以这样:

function buildAnimal(animalData){
    let {accessory, animal, color, hairType} = animalData;
    ...
}

animalData的对象属性给到变量:accessory, animal, color, hairType

console.log(accessory);//horn
console.log(animal); //horse
...
你可能要问,如果是多层嵌套的对象怎么解构?
比如:
```javascript
let person = {
    name: 'Maya',
    age: 30,
    phone: '123',
    address:{
        zipcode: 1234,
        street: 'rainbow',
        number: 42
    }
}




class="se-preview-section-delimiter">div>

我们可以这么做:

let {address: {zipcode, street, number}} = person;
console.log(zipcode, street, number); //1234 rainbow 42




class="se-preview-section-delimiter">div>

或者:

let {zipcode, street, number} = person.address;
console.log(zipcode, street, number); //1234 rainbow 42




class="se-preview-section-delimiter">div>

可能有人说我们需要,我们的变量名需要和属性名一样。实际上不需要。我们可以重新修改它的名字:比如

let {name: fullName} = person;
console.log(fullName); //Maya
console.log(name); //ReferenceError: name is not defined.




class="se-preview-section-delimiter">div>

解构数组

比如我们定义这样一个数组:

var arr = ["one", "two", "three", "four"];




<div class="se-preview-section-delimiter">div>

这一次我们左边就不能用{},而应该用[]:

var [first, second] = arr; //解构开始的两个元素
var [,,third, four] = arr; //解构最后的两个元素 【行2】
var [one, two, three, four] = arr //解构所有元素




class="se-preview-section-delimiter">div>

说明:如果不要解构某一个元素,直接逗号隔开就行了,参考:【行2】。要注意的是逗号的位置和数量。
解构嵌套数组:

var arr2 = [['one', 'two'], 'three', 'four'];
var [[one, two]] = arr2; //one = 'one', two = 'two'




class="se-preview-section-delimiter">div>

解构可遍历的对象:比如Map,Set,字符串等

var [a, b] = new Set([1,2]); //a = 1, b = 2;
var [a, b] = new Map([[1,2], [2,3]]); //a= [1,2], b = [2,3]
var [x, y] = "xyz"; //x = "x", y = "y"




class="se-preview-section-delimiter">div>

解构赋值

多个变量的声明和初始化:

let a, b, c, d;
a = 2;
b = 3;
c = { id: 4 };
d = 5;
//Or: let a = 2, b = 3, c = { id: 4 }, d = 5;




class="se-preview-section-delimiter">div>

解构赋值的话,我们可以这么写:

let a, b, c, d;
[a, b, c, d] = [2, 3, { id: 4 }, 5];
//Or: let [a, b, c, d] = [2, 3, { id: 4 }, 5];




class="se-preview-section-delimiter">div>

解构带上默认值

如果我们要解构的对象的属性没有值,甚至属性不存在。这个时候,我们需要一个默认值:
通常我们可能会这么写:

let name = person.name || "default name"; // and so on




class="se-preview-section-delimiter">div>

在解构里面,我们可以这么写:

let {name = "default name"} = obj;




<div class="se-preview-section-delimiter">div>

如果属性不存在,name 会被赋值一个默认的值。
或者:

let {name: myFullName = "default name"} = obj;




<div class="se-preview-section-delimiter">div>

如果属性不存在,myFullName 会被赋值一个默认的值。

多参数: …操作符

比方说我们有一个数组,我们想要数组的第一个元素,剩余的元素用作其他用途。
一般我们会这么写:

let first = arr[0],
    rest = arr.slice(1);




<div class="se-preview-section-delimiter">div>

ES6解构我们可以这么写:

let [first, ...rest] = arr;
console.log(first);// "one"
console.log(rest); //["two", "three", "four"]




class="se-preview-section-delimiter">div>

注意:…操作符只能放到最后。

let [...rest, last] = arr;
//SyntaxError: Rest element must be last element




class="se-preview-section-delimiter">div>

交换

function swap(arr, i, j){
    let temp = arr[i];
    arr[i] = arr[j];
    arr[j] = temp;
}




class="se-preview-section-delimiter">div>

我们经常会有上面的交换两个元素的代码。
有了解构以后,我们可以这么写:

function swap(arr, i, j){
   [arr[i], arr[j]] = [arr[j], arr[i]];
}




class="se-preview-section-delimiter">div>

解构在函数中的好处

在上面的例子中,我们是这么做的:

function buildAnimal(animalData){
    let {accessory, animal, color, hairType} = animalData;
    console.log(`I'm a ${color} ${animal} with ${accessory} and ${hairType} hair`};
}




实际上,我们希望直接从参数列表里解构出来:

function buildAnimal({accessory, animal, color, hairType}}{...}




甚至可以定义默认值:

function buildAnimal({accessory = "", animal = "cat", color = 'rainbow', hairType = 'straight'}){...}




class="se-preview-section-delimiter">div>

调用的方式这样:

buildAnimal({accessory = "horn", animal = "horse", color = 'purple', hairType = 'curly'}};
//I'm a purple horse with a horn and curly hair.




class="se-preview-section-delimiter">div>

注意一点:如果我们要默认参数,我们需要传递一个对象进去:

buildAnimal({}); //Works
buildAnimal(); //Not working.




class="se-preview-section-delimiter">div>

我们能不传递一个空对象吗?可以。

function buildAnimal({accessory = "", animal = "cat", color = 'rainbow', hairType = 'straight'} = {}){...}




class="se-preview-section-delimiter">div>

我们给我们的参数一个默认的值:{}

数组也是类似:

function sum([a = 0, b = 0, c = 0]=[]) { return a + b + c;}
console.log(sum([1, 2, 3])); //6
console.log(sum()); //0




class="se-preview-section-delimiter">div>

解构不好的地方

1 我们不能解构,如果没有采用声明的语法,或者()包起来
因为解构是以{}开头,而{}在JavaScript中当做一个块,而不是对象常量。

let a, b;
{a, b} = {a: 1, b: 2}; //Error!!!
({a,b}) = {a: 1, b: 2}; //Error!!
({a, b} = {a: 1, b: 2}); //OK

2 嵌套对象的属性必须存在否则会解构失败

以上就是今天的主要内容,感谢阅读。

原文链接,点击阅读原文

## 解构不好的地方
1 我们不能解构,如果没有采用声明的语法,或者()包起来
因为解构是以{}开头,而{}在JavaScript中当做一个块,而不是对象常量。
```javascript
let a, b;
{a, b} = {a: 1, b: 2}; //Error!!!
({a,b}) = {a: 1, b: 2}; //Error!!
({a, b} = {a: 1, b: 2}); //OK

2 嵌套对象的属性必须存在否则会解构失败

以上就是今天的主要内容,感谢阅读。

原文链接,点击阅读原文
https://medium.com/front-end-hacking/es6-cool-stuffs-destructuring-me-plz-b8f1335d241a
作者知乎/公众号:前端疯
ES6非常棒的特性-解构_第1张图片

你可能感兴趣的:(Es6)