ES6(5)—— 解构赋值

 

一、什么是解构赋值?它的基本用法。

ES6允许按照一定模式从数组和对象中提取值,然后对变量进行赋值,这被称为解构。

//下面四句分别是对a,b,c分别赋值
let arr = [1,2,3];
let a = arr[0];
let b = arr[1];
let c = arr[2];

//下面一句话搞定上面的四句话,这就是解构赋值
let [a,b,c] = [1,2,3];
//这是JSON解构赋值
let {a,b,c} = {a:1,b:2,c:3};
//复杂结构的解构赋值
let [{a,b},[n1,n2,n3],num,str] = [{a:1,b:2},[6,7,8],10,'hello']
console.log(a,b,n1,n2,n3,num,str);     //1,2,6,7,8,10,hello

二、解构赋值的要求

  1. 左右两边结构必须一样
  2. 右边必须是个东西
  3. 声明和复制不能分开(必须在一起完成)

三、解构不成功和不完全解构

1、结构不成功:结构不成功,变量的值就会等于undefined

let [x,y,...z] = ['a'];    //这是解构不成功
//x = a;
//y = undefined
//z = []

2、不完全解构,但是解构还是可以成功的。

//这是不完全解构,但是也可以解构成功
let [x,y] = [1,2,3];
//x = 1;
//y = 2;

3、如下方式都是会报错的结构。事实上,某种数据结构具有IIterator接口,就可以才有数组形式的解构赋值。

let [foo] = 1;
let [foo] = false;
let [foo] = NaN;
let [foo] = undefined;
let [foo] = null;
let [foo] = {}; 
//报错原因:等号右边的值或是转为对象以后不具备Iterator接口(前五个),或是本身就不具备Iterator接口(最后一个表达式)   

 四、解构赋值允许指定默认值

1、解构赋值如何指定默认值

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

 2、ES6内部使用严格相等运算符(===)判断一个位置是否有值,所以如果一个数组成员不严格等于undefined,默认值就不会生效。

let [x = 1] = [undefined]          //x=1
let [x = 1] = [null]               //x=null,原因是null不严格等于undefined

3、默认值可以引用解构赋值的其他变量,但是该变量是必须声明过的。

let [x = y,y = 1] = [];         //ReferenceError,原因是x用到y的时候,y还没有声明

五、对象的解构赋值 
       1、对象的解构与数组的解构有一个重要的不同。数组的元素是按次序排列的,变量的取值是由它的位置决定的,而对象的属性没有次序,变量必须与属性同名才能取到正确的值。如果左边的变量名在右边找不到相对应的属性名,则就会等于undefined。

let {bar,foo} = {foo:'aaa',bar:'bbb'}
//bar = bbb
//foo = aaa

2、如果变量名与属性名不一致,则可以按照如下方式书写

var {foo:baz} = {foo:'aaa',bar:'bbb'};
//baz="aaa"

3、实际上对象的解构赋值是按下面形式的简写

let {foo:foo,bar:bar} = {foo:'aaa',bar:'bbb');

4、对象赋值的内部机制是先找到同名属性,然后再赋值给的对应的变量。真正被赋值的是前者,而不是后者。

let {foo:baz) = {foo:'aaa',bar:'bbb'};
//baz = "aaa"
//foo:foo is not defined
//foo是匹配模式,baz才是变量,真正被赋值的是baz,而不是模式foo

5、解构也可以用于嵌套解构的对象

let obj = {
    p:[
        'hello',
        {y:'World'}
    ]
};
let {p:[ { x , { y } ] } = obj;

//x="Hello"
//y="World"
//p是匹配模式,笔试变量,因此不会被赋值

//如果p要作为变量被赋值,可以这样写
let obj = {
    p:[
        'hello',
        {y:'World'}
    ]
};
let {p,p:[ { x , { y } ] } = obj;
//x="Hello"
//y="World"
//p=["hello",{y:"world"}];

6、对象的解构也可以指定默认的值。默认值生效的条件是,对象的属性值严格等于undefined。

var {x = 3} = {x:undefined};
//x=3

var {x = 3} = {x:null};
//x=null

7、 如果解构失败,变量的值就会等于undefined。

let {foo} = {bar:"baz"};
//foo = undefined

8、如果解构模式是嵌套的对象,而且子对象所在的父属性不存在,那么将会报错。

let { foo: { bar } } = {baz:'baz'};
//foo属性对应一个子对象。该子对象的bar属性在解构时会报错。原因是,因为foo此时等于undefined,再取子属性就会报错

10、如果将一个已经声明的变量解构赋值,必须非常小心。

let x;
{x} = {x:1};
//SyntaxError:syntax error。原因是JavaScript会把{x}理解为一个代码块,从而发生语法错误。只要不将大括号写在首行,就可以避免这个问题。

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

11、圆括号与解构赋值的关系。解构赋值允许等号左边的模式之中不放置任何变量名。因此可以写出如下表达式。

( {} = [true,false]);
( {} = 'abc' );
( {} = [] );

12、对象的解构赋值可以很方便地将现有对象的方法赋值到某个变量。

let { log, sin, cos } = Math;
将Math对象的对数,正弦,余弦三个方法赋值到对应的变量上,使用起来就会很方便。

13、由于数组也是对象,因此可以对数组进行对象属性的赋值。

let arr = [1,2,3];
let { 0:first,[arr.length-1]:last } = arr;

//first = 1
//last = 3

六、字符串的解构赋值

1、字符串也可以解构赋值,这是因为每一个字符被转换成了一个类似数组的对象。

const [a,b,c,d,e] = 'hello';
//a='h'
//b='e'
//c='l'
//d='l'
//e='o'

2、类似数组的对象有一个length属性,因此可以对这个属性进行解构赋值。

let { length:len } = 'hello';
// len=5

七、数值和布尔值的解构赋值

1、解构赋值时,如果等号右边是数值和布尔值,则会先转为对象。解构赋值的规则是,只要等号右边不是对象或者数组,就像将其转化为对象。undefined和null无法转换为对象,会报错。

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

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

八、函数参数的解构赋值

1、函数参数也可以使用解构赋值

[ [1,2] , [3,4] ].map(([a,b]) => a+b);
// [3,7]

2、函数参数的解构也可以设置默认值。

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]


//如下写法就会和上面的结果不一样,代码是为函数move参数设置了默认值,而不是为变量x和变量y指定默认值,所以与前一种写法不同的结果。

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]


//undefined会触发函数的默认值
[1, undefined, 3].map((x = 'yes' => x);
//[1, 'yes', 3]

九、圆括号问题

解构赋值,对于编译器来说,到底是模式还是表达式,没有办法一开始就知道,要解析到等号才知道。因此,带来了一个心得问题,如果模式种出现圆括号该怎么处理?ES6的规则是,只要有可能导致解构的歧义,就不得使用圆括号。因此建议,只要有可能,就不要在模式中放置圆括号。

1、不能使用圆括号的三种情况

(1)变量声明语句

//变量声明语句,模式不能使用圆括号
let [(a)] = [1];
let {x:(c)} = {};
let ( {x:c} ) = {};
let { (x:c) } = {};
let {(x):c} = {};
let { o:({p: p}) } = {o:{p:2}};

(2)函数参数

//都会报错
function f([z]) { return z; };
function f([z, (x)]) { return x; };

(3)赋值语句的模式

//会报错
({ p:a }) = { P: 42 }
([a]) = [5]
[({ p:a }), {x:c}] = [{},{}];

2、可以使用圆括号的情况

(1)可以使用圆括号的情况只有一种,赋值语句的非模式部分可以使用圆括号。

[(b)] = [3];                   //模式是取数组的的第一个成员
({ p:(d) } = {}];              //模式是p不是d
[(parseInt.prop)] = [3];       //

//上面的语句都是赋值语句,而不是声明语句,另外他们的圆括号不属于模式的一部分。

十、解构赋值的用途

1、可以交换变量的值

let x = 1;
let x = 2;
[x,y] = [y,x];

2、从函数返回多个值

//函数只能返回一个值,如果要返回多个值,只能将它们放在数组或对象里返回。
//返回数组
function example(){
    return [1,2,3];
}

//返回对象
function example(){
    return {
        foo:1,
        bar:2
    }
}

3、函数参数的定义(解构赋值可以方便地将一i组参数与变量名对应起来)

//有次数
function f([x,y,z]) {...}
f([1,2,3]);


//无次序
function f([x,y,z]) {...}
f([x:3,y:2,z:1]);

4、提取JSON数据

let jsonData= {
    id:41,
    status:"ok",
    data:[867,5309]
};
let {id,status,data} = jsonData;

//id=42
//status = "ok"
//data=[867,5309]

5、函数参数的默认值

jQuery.ajax = function (url,{
    async = true,
    beforeSend = function(){},
    cache = true,
    complate = function(){},
    crossDomain = false,
    gloabal = true,
    //more config
}){
    //do stuff
};

6、遍历Map解构(任何部署了Iterator接口的对象都可以用for...of循环遍历。Map结构原生支持Iterator接口,配合变量的解构赋值获取键名和键值就非常方便了)。

var map =  new Map();
map.set("first","hello");
map.set("second","world");

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

//first is hello
//second is world

//只获取键值
for(let [,value] of map){
    //...
}

//只获取键名
for(let [value] of map){
    //...
}

十二、输入模块的指定方法

加载模块时,往往需要指定输入的方法。解构赋值使得输入语句非常清晰。

const { SourceMapConsumer, SourceNode } = require("source-map");

 

 

参考:阮一峰的ES6入门的第三版

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值