解构赋值

​这个语法在es6中很常见,不得不掌握啊

什么是解构赋值,就是按照一定模式从数组和对象中提取值,然后又按照这个模式对变量进行赋值

就是可以理解为,写个和这个对象或数组结构类似的自定义对象或数组,里面写上要用的变量(注意结构是一一对应的,所以值和变量),然后两个对象或数组通过=运算符连接即可。这样大大简化了代码量,提高了效率

 

数组的解构赋值

  1. 解构不成功,变量的值就会为undefined

  2. 可以进行不完全解构,即等号左边的模式只匹配一部分等号右边的数组

  3. 如果等号右边不是数组(或者说不是可遍历结构),会报错

  4. 只要某种数据结构具有Iterator接口,都可以采用数组形式进行解构赋值

  5. 可以指定默认值,即在对应的位置的值为undefined时生效(判断该位置的值是否为undefined时,使用的是===运算符)

  6. 当指定默认值且这个默认值为一个表达式时,则这个表达式只会在用到的时候再去运算求值(默认是不会直接进行求值的)

  7. 默认赋值也可以引用解构赋值的其他变量,但这个变量必须已经声明

{  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}

对象的解构赋值

  1. 对象的属性没有次序之分,变量必须与属性同名才能取到正确的值(同名时,即使顺序不同也可以)

  2. 解构失败,变量的值为undefined

  3. 如果变量名与属性不同名,那么可以将变量变为属性:值形式,即给变量加个属性名,这个属性名与要取值的属性名相同(就是写个相同的键值对,键相同,值与值也会相同)

  4. 要解构具有嵌套结构的对象,必须写个具有同样嵌套结构的对象,该对象中将变量写为值,属性名与解构对象相同

  5. 解构具有嵌套结构的对象,但子对象所在的父属性不存在,则会报错

  6. 也可以指定默认值,用法同数组,只有当对象的属性值严格等于undefined时才生效

  7. 对数组也能进行解构

  8. 给已经声明的变量进行解构赋值时,要使用圆括号

{  //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}

数值和布尔值的解构

首先,我认为这种解构的存在并无多大意义。然后,我确实获取不了解构的值。嘿嘿,得不到的就是酸的

  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]}

 

你可能感兴趣的:(JavaScript,解构赋值,JS中解构赋值)