这个语法在es6中很常见,不得不掌握啊
什么是解构赋值,就是按照一定模式从数组和对象中提取值,然后又按照这个模式对变量进行赋值
就是可以理解为,写个和这个对象或数组结构类似的自定义对象或数组,里面写上要用的变量(注意结构是一一对应的,所以值和变量),然后两个对象或数组通过=运算符连接即可。这样大大简化了代码量,提高了效率
数组的解构赋值
解构不成功,变量的值就会为undefined
可以进行不完全解构,即等号左边的模式只匹配一部分等号右边的数组
如果等号右边不是数组(或者说不是可遍历结构),会报错
只要某种数据结构具有Iterator接口,都可以采用数组形式进行解构赋值
可以指定默认值,即在对应的位置的值为undefined时生效(判断该位置的值是否为undefined时,使用的是===运算符)
当指定默认值且这个默认值为一个表达式时,则这个表达式只会在用到的时候再去运算求值(默认是不会直接进行求值的)
默认赋值也可以引用解构赋值的其他变量,但这个变量必须已经声明
{
let [a,b,c]=[1,2,3];
console.log(a);//1
console.log(b);//2
console.log(c);//3
}
{
//注意看这两个例子的区别,有点小坑
let [a,b,c]=[1,[2,3],[4]];
console.log(a);//1
console.log(b);//[2,3]
console.log(c);//4
let [a_2,[b_2],c_2]=[1,[2,3],[4]];
console.log(a_2);//1
console.log(b_2);//2
console.log(c_2);//4
}
{
let [a,...b]=[1,[2,3],[4],5];
console.log(a);//1
console.log(b);//[[2,3],[4],5]
}
{
let [a]=[];
console.log(a);//undefined
}
{
let [a,b]=[1,2,3];
console.log(a);//1
console.log(b);//2
}
{
let [,,a]=[1,2,3];
console.log(a);//3
}
{
let [a]=1;
console.log(a);
//Uncaught TypeError: 1 is not iterable
// at 04.html:49
}
//默认值
{
let [a=1]=[2];
console.log(a);//2
}
{
let [a=1]=[];
console.log(a);//1
}
{
let [a=1]=[undefined];
console.log(a);//1
}
{
let [a=1]=[null];
console.log(a);//null
}
// 默认值为表达式
{
function foo(){
console.log('aaa');
}
let [a=foo()]=[1];
console.log(a);//1
}
{
function foo(){
console.log('aaa');
}
let [a=foo()]=[undefined];
console.log(a);
//aaa
//undefined
}
//引用解构赋值的其他变量
{
let [x=1,y=x]=[];
console.log(x,y);//1 1
}
{
let [x=1,y=x]=[2];
console.log(x,y);//2 2
}
{
let [x=y,y=1]=[];
console.log(x,y);
//Uncaught ReferenceError: Cannot access 'y' before initialization
//at 04.html:101
}
对象的解构赋值
对象的属性没有次序之分,变量必须与属性同名才能取到正确的值(同名时,即使顺序不同也可以)
解构失败,变量的值为undefined
如果变量名与属性不同名,那么可以将变量变为属性:值形式,即给变量加个属性名,这个属性名与要取值的属性名相同(就是写个相同的键值对,键相同,值与值也会相同)
要解构具有嵌套结构的对象,必须写个具有同样嵌套结构的对象,该对象中将变量写为值,属性名与解构对象相同
解构具有嵌套结构的对象,但子对象所在的父属性不存在,则会报错
也可以指定默认值,用法同数组,只有当对象的属性值严格等于undefined时才生效
对数组也能进行解构
给已经声明的变量进行解构赋值时,要使用圆括号
{ //a,b是变量,与属性同名
let {a,b}={a:'1',b:'2'};
console.log(a,b);//1 2
}
{ //a,b是变量,与属性不同名
let {foo:a,bar:b}={foo:'1',bar:'2'};
console.log(a,b);//1 2
}
{ // 解构嵌套结构的对象
let obj={
stu:{
name:'小李',
age:20,
scores:[
{math:'69'},
{english:'96'}
]
}
}
let {
stu:new_stu,
stu:{
name:new_name,
age:new_age,
scores:new_scores,
scores:[
new_math,
new_english
]
}
}=obj;
console.log(new_stu);
/*
{name: "小李", age: 20, scores: Array(2)}
age: 20
name: "小李"
scores: Array(2)
0: {math: "69"}
1: {english: "96"}
*/
console.log(new_name);//小李
console.log(new_age);//20
console.log(new_scores);
/*
(2) [{…}, {…}]
0: {math: "69"}
1: {english: "96"}
*/
console.log(new_math);//{math: "69"}
console.log(new_english);//{math: "69"}
}
{
let obj={};
let arr=[];
({foo:obj.a,bar:arr[0]} = {foo:'小李',bar:20});
console.log(obj.a);//小李
console.log(arr[0]);//20
}
{ //默认值
let {x=3}={};
console.log(x);//3
//此时,y才是变量,x只是属性名
let {x:y=3}={};
console.log(y);//3
//此时a有值,所以默认值不会生效
let {a:b=5}={a:1};
console.log(b);//1
//q没有值,默认值生效
let {q:c=3}={q:undefined};
console.log(c);//3
let {w:e=4}={w:null};
console.log(e);//null
}
{
let y;
({y} = { y:'20'});//不报错
console.log(y);//20
let x;
{x} ={x:2};
console.log(x);//报错
}
{ //解构数组
let arr=[2,1,4];
let {0:a,1:b,2:c}=arr;
console.log(a,b,c);//2 1 4
}
字符串解构
字符串能被解构,是因为在解构时被包装成了String对象
{ //空格也被解析了
let [a,b,c,d,e,f,g,h]='hello js';
console.log(a,b,c,d,e,g,h);//h e l l o j s
console.log("1"+"2");//12
console.log("1"+f+"2");//1 2
}
数值和布尔值的解构
首先,我认为这种解构的存在并无多大意义。然后,我确实获取不了解构的值。嘿嘿,得不到的就是酸的
对数值和布尔值进行解构时,数值和布尔值会先被转换为对象,然后进行解构。但是,也确实无法获取到这个数值和布尔值
对于不是对象或数组的值,比如null和undefined,进行解构时就会报错
{
let {toString:q}='hello world';
console.log(q);//ƒ toString() { [native code] }
}
{
let {toString:a}=123;
console.log(a);//ƒ toString() { [native code] }
console.log(a===Number.prototype.toString);//true
//a等同于是Number的原型链上的toString,123本身并不具有任何方法
let {toString:b}=true;
console.log(b);//ƒ toString() { [native code] }
console.log(b===Boolean.prototype.toString);//true
}
{ //这是将数值转换为对象
let a=new Number(123);
console.log(a.toString());//123
console.log(a);
/*
Number {123}
__proto__: Number
[[PrimitiveValue]]: 123
*/
}
{
let{prop:x}=null;
console.log(x);//Uncaught TypeError:
let {prop:y}=undefined;
console.log(y);//Uncaught TypeError:
}
函数参数解构赋值
用法就与上面的数组和对象解构类似,只是这个是作为参数使用
这里比较需要注意的地方就是参数默认值和解构默认值的区别(感觉自己有点小机智)
{
function foo([x,y]){
console.log(x+y);
}
foo([2,3]);//5
function bar({x,y}){
console.log(x+y);
}
bar({x:3,y:3});//6
}
{
//这是解构默认值
function foo_2({x=3,y=4}){
console.log(x,y);
}
foo_2();//报错
foo_2({});//3 4
foo_2({x:1});//1 4
//这是参数默认值
function bar_2(x=3,y=4){
console.log(x,y);
}
bar_2();//3 4
bar_2({});//{} 4
bar_2({x:1});//{x: 1} 4
// 这是参数默认值+解构默认值
function foo({x=3,y=4}={}){
console.log(x,y);
}
foo();//3 4
foo({});//3 4
foo({x:1});//1 4
foo({z:2});//3 4
//这是参数默认值+解构
function bar({x,y}={x:3,y:4}){
console.log(x,y);
}
bar();//3 4
bar({});//undefined undefined
bar({x:1});//1 undefined
bar({z:2});//undefined undefined
/*
仔细看这个四个函数,对比一下:推荐使用参数默认值+解构默认值(双重默认值,有备无患)
第一个函数,无法执行foo_2(),为什么?
foo_2()函数中参数是一个对象,该对象中有默认值了,但是这个默认值生效的前提是
能进行解构,能进行解构的前提是有对象让它解构。但是,直接执行foo_2()而没有传入
对象,那么函数中的参数就没有对象,也就无法进行解构,自然报错
第二个函数,全都能执行,为什么?
执行时,不传入值,就使用定义好的。传入值,那就按照顺序将值赋值给参数,然后这个参数
按照这个值进行运算。就是,不管你有么有传值,它都一个备用方案
我认为第三个和第四个函数都使用了参数默认值,都是{}={}这种形式,实际参数是一个对象
第三个函数 参数默认值+解构默认值
这是最优方案,为什么呢?
执行时,如果有值,首先会顶替掉这个空对象,然后对这个传入的值进行解构,解构失败时就会返回默认值。
如果没有值出传入,就更好了,直接使用默认值。不管如何,都不会报错或是出现undefined
第四个函数 参数默认值+解构
这是比较次级的方案,不是很推荐,因为会产生undefined,可能在运算时会报错
执行时,如果有值传入,首先也是顶替掉{x:3,y:4},然后对传入的值进行解构。但是注意,当解构失败时,
是没有默认值的,只能返回undefined,这一点很不好。然后当没有值传入时才会使用原本的参数默认值进行
解构
*/
}
圆括号问题
这个问题也是要小心,处理不当会报错
专家建议,只要有可能就不要在模式中使用圆括号
以下三种方式不能使用圆括号
// 1.变量声明语句
{ //全都报错
let [(a)]=[1];
let {x:(c)}={};
let {(x:c)}={};
let ({x:c})={};
let {(x):c}={};
let {x:({p:p})}={x:{p:2}};
}
// 2.函数参数
{
//报错
function f([(x)]){
console.log(x);
}
function b([z,(x)]){
console.log(z,x);
}
}
// 3.赋值语句的模式
// 都报错
({p:a})={p:2};
([a])=[5];
[({p:a})]=[{}];
以下都是可以使用圆括号
{
[(b)]=[3];
({p:(c)}={});
console.log(b,c);//3 undefined
}
用途
这个就很多了,简单说几个
{ //交换变量的值
let x=1;
let y=3;
[x,y]=[y,x];
console.log(x,y);//3 1
}
{
//取值方便
function foo(){
return [1,2,3];
}
let [a,b,c]=foo();
console.log(a,b,c);//1 2 3
function bar(){
return {
a:1,
b:2
}
}
let { a:qq,b:ww}=bar();
console.log(qq,ww);// 1 2
}
{
//提取JSON值
let jsonData={
"id":012,
"status":200,
"data":[123,434]
}
let {id,status,data:arr}=jsonData;
console.log(id,status,arr); //10 200 [123, 434]
}