解构赋值

什么是解构赋值?
解构赋值:ES6允许按照一定的模式从数组和对象中取值,然后进行对变量进行赋值,这被称为解构赋值。
解构赋值的分类:

一、数组解构赋值

简单的数组的解构

//例1:
{
	let a,b;
	[a,b]=[1,2];
	console.log(a,b) //输出 a=1  b=2;
}

含有扩展运算符(…)的解构

//例2:
{
	let a,b,c;
	[a,b,...c]=[1,2,3,4,5,6];
	console.log(a,b,c) //输出 a=1  b=2  c=[3,4,5,6];
}

当解构不成功或者解构不完全的时候

// 例3:
{
	let a,b,c;
	[a,b,c]=[1,2];
	console.log(a,b,c);//输出 a=1  b=2  c=undefined;
}

//例4:
{
	let a,b;
	[a,b]=[1,2,3];
	console.log(a,b);//输出  a=1  b=2;
}

数组的解构赋值,要求等号两边的结构格式要相同,才能完全结构。
上面代码例子1:
其中[a,b]=[1,2],两边的结构是完全相同的,那么就完全解构,1赋值给a,2赋值给b。

例子代码2:
其中引入新的运算符-----扩展运算符(…),用于取出参数对象中的所有可遍历属性,拷贝到当前对象之中。[a,b,…c]=[1,2,3,4,5,6],1赋值给a,2赋值给b,加了扩展运算符的c,那么…c=[3,4,5,6],这就是扩展运算符。

例子代码3:[a,b,c]=[1,2],a,b会挨个被赋值为1,2,但是等号右边已经没有值了,那么c就是已经定义了,但是这里没有赋值给它,那么c等于undefined。

例子代码4:右边多了数值,就会自动丢弃,不会赋值给左边的变量。

默认值

//例子5:
{
	let foo;
	[foo=12]=[];
	console.log(foo)  //输出 12;
}
//例子6:
{
    let[x,y="b"]=["a",undefined]// x="a" ,y="b"
}

//例子7
{
	let a=2;
    [a]=["undefined"];
    console.log(a); //输出  a="undefined"
}

解构赋值是允许设定默认值的,但是只有undefined才会触发使用默认值。

例子代码5:[foo=12]=[],因为右边是一个空的,没有值,那么右边就相当于undefined,那么就会触发使用foo的默认值12,所以输出12。

例子代码6:[x,y=“b”]=[“a”,undefined],x会被赋值为字符串“a”,因为y对应过去是undefined,那么触发使用默认值,所以y=“b”。

例子代码7:如果是这种“undefined”的话,那么就不会触发默认值,“undefined”就是一个字符串。

解构顺序

//例子8
{
    let[x=1,y=x]=[2]
    console.log(x,y) //  x=2  y=2
}

先把2赋值给x,这时x已经是2了,再进行对y的解构赋值,因为是undefined,那么触发使用默认值,y=x,这时x=2,那么y=2。这就是数组解构赋值的顺序。

二 、对象的解构赋值

对象的解构赋值与数组有一个重要的不同。数组的元素是按顺序进行排列的,变量的取值是由它的位置决定的,而对象的属性是没有次序的,变量必须与属性同名,而且等号两边的结构和格式是一模一样的,这样才能取到正确的值。
例如:

//例子9
{
	let {bar,foo}={foo:"aaa",bar:"bbb"}
	console.log(foo,bar); //输出  foo="aaa"  bar="bbb"
}
//例子10
{
	let {baz}={foo:"aaa",bar:"bbb"};
	console.log(baz);//输出 undefined
}
//例子11
{
    let{x,y,z=1,a:q}={a:100,b:200,y:300}
    console.log(x,y,z,q);// x=undefined  y=300 z=1 q=100
}

上面代码的第一个例子中,等号左边与等号右边变量的次序没有挨着次序对齐,但是对象的解构赋值是不影响的,是通过属性名来进行赋值的。

第二个代码例子的变量没有对应相同的属性名,导致取不到值,最后就等于undefined。

上述两个例子的书写都是对象解构赋值的简写。实际上:

{
 let {bar:bar,foo:foo}={foo:“aaa”,bar:“bbb”}
 console.log(foo,bar); //输出 foo=“aaa” bar=“bbb”
 }


对象的解构赋值的内部机制是先找到相同属性名的,然后进行赋值给对应的变量,其实真正被赋值的是后者,而不是前者。
例如:

//例子12
{
	let{foo:baz}={foo:"aaa",bar:"bbb"};
	console.log(baz);//输出 baz="aaa"
	console.log(foo);//输出 将会报错  error:foo is not defined
}    //foo是一个属性名而不是一个变量,赋值是baz被赋值“aaa”。

三、字符串的解构赋值

字符串也可以进行解构赋值,这时候的字符串就被转换为一个类似数组的对象。

{
	let[a,b,c,d,e]="hello";
	console.log(a,b,c,d,e); //输出 a="h" b="e" c="l" d="l" e="o"
}

类似数组的对象都有一个length属性,同时还可以对这个属性进行解构。
例如

{
	let{length:len}="hello";
	console.log(len); //输出 len=5

四、圆括号问题

以下三种解构赋值不得使用圆括号。

1.变量声明语句

let [( a )]=[1];
 let {x: ( c )}={};
 let {(x: c)}={};
 let {(x):c}={};


以上语句都会报错,因为都是变量声明语句。
2.函数参数
function f([(z)]){ return z;} 报错
function f([z,(x)]){ return x;} 报错
因为函数参数也属于变量声明。
3.赋值语句的模式
({p:a})={p:10}; 报错
([a])=[5]; 报错
上面语句把整个模式放在圆括号里,导致报错。

那么可以使用圆括号的情况
例如
[(b)]=[3]; 正确
({p:(d)}={}); 正确
[(parseInt.prop)]=[3] 正确
上面三行语句都可以正确执行,因为首先它们都是赋值语句,而不是声明语句;其次它们的圆括号都不属于模式的一部分。第一行语句中,模式是取数组的第一个成员,跟圆括号无关;第二行语句中,模式是p,而不是d;第三行语句与第一行语句的性质一致。

五、用途和运用场景

交换变量的值

以往的变量交换需要中间变量来暂时存储值,显得复杂。
利用解构赋值交换变量
例如

{
	let x=1;
	let y=2;
	[x,y]=[2,1];
	console.log(x,y)// 输出 x=2 y=1;
}

从函数返回多个参数

函数只能返回一个值,如果想返回多个值,只能把它们放在数组和对象里返回,有了解构赋值,从中取值就更加的方便。
例如

{
	function f1(){
		return [1,2,3]
	}
	let [a,b,c]=f1(); //输出 a=1 b=2 c=3
}
{
	function f2(){
		return{
		foo:1,
		bar:2
		};
	};
	let {foo,bar}=f2();  //输出  foo=1 bar=2
}

提取JSON数据

在后台服务器传输来的数据,大多是JSON格式,那么要提取有用的数据,用解构赋值就会非常的容易。
例如

{
	let jsonData={
		id:42,
		status:"OK",
		data:[867,5309]
	};
	let{id,status,data:number}=jsonData;
	console.log(id,status,number)//  输出  42 OK  [867,5309]
}

其他

比如数据的提取与舍去

{
    let [b,,,c]=[1,2,3,4]
    console.log(b,c);//输出 b=1  c=4;
}

{
    let [a,...b]=[1,2,3,4,5]
    console.log(a,b); //输出 a=1  b=[ 2, 3, 4, 5 ]
}