一文看懂 ES6 解构赋值

一、什么是解构赋值

ES6中,通过解构赋值,可以将属性 / 值对象 / 数组中取出,赋值给其他变量的操作就是解构赋值。

在下图上可以发现左侧和右侧都必须是数组,左侧可以定义 n 个变量,那么与之对应的右侧也需要有相应个数的变量值,我们左侧的变量从右侧取值的操作就是解构赋值

二、数组解构

在上面的图示里可以看出来,数组解构就是从数组中提取值,只要等号两边的模式相同,左边的变量就会在右侧的数组里查找对应位置的值进行赋值操作。

数组结构的应用主要有:

  • 对一维数组解构

  • 对多维数组解构

  • 对字符串解构

  • 对...扩展运算符解构

1. 一维数组解构

传统的变量赋值是这样的:

let arr = [1,2,3];//把数组的值分别赋给下面的变量;
let a = arr[0];
let b = arr[1];
let c = arr[2];

console.log(a); // a的值为1
console.log(b); // b的值为2
console.log(c); // c的值为3

变量的解构赋值:

let [a,b,c] = [1,2,3];  //把数组的值分别赋给下面的变量;
console.log(a); // a的值为1
console.log(b); // b的值为2
console.log(c); // c的值为3

左侧是数组,右侧也是数组。

左侧的变量会根据索引,依次获取右侧数组里的值。

代码短了很多,可读性也很强,这种叫做数组的解构赋值

一句话:按索引取值~!

  • 不完全解构

    当左边的模式(你可以理解为格式)与右边不完全一样的时候,那么赋值过程中,只会给模式匹配成功的部分的变量赋值。

    • 没得到的值的变量,返回的就是 undefined。相当于只声明了变量,但是没赋值。

    • 没有变量存储的值,就会被浪费掉。

let [a] = [];      // a = undefined  

let [name,age,add] = ["Lily", , "Chongqing"];
console.info( name );  // Lily
console.info( age );   // undefined
console.info( add );   // Chongqing
let [x, , z] = [1, 2, 3];   //x=1,z=3  

// 传统写法
let arr = [1, 2, 3];
let x = arr[0];
let z = arr[2];
  • 左侧变量可以设定默认值

如果变量的值取到了 undefined ,那么左侧变量返回的就是默认值。否则,就是右侧设定的值。

let [name="Lily",age=18] = [ "Mouse",  20 ] ;   //  age = 20 

let [name="Lily",age=18] = [ "Mouse",  0 ] ;   //  age = 0 
let [name="Lily",age=18] = [ "Mouse",  NaN ] ;   //  age = NaN 
let [name="Lily",age=18] = [ "Mouse",  null ] ;   //  age = null 

let [name="Lily",age=18] = [ "Mouse" ] ;   //  age = 18 
let [name="Lily",age=18] = [ "Mouse" , undefined ] ;   //  age = 18 
  • 可以用来交换变量数据
let a = 1;
let b = 2;
[a,b] = [b,a];
console.info(a,b);  // 2 1

2. 多维数组结构

let arr1 = [1,[2,3],4];
let [a1, [b1,c1,d1], e1] = arr1; 
console.info( a1,b1,c1,d1,e1);  // 1,2,3,undefined,4

按照索引对应就行。

如果两侧不一致:

let [a,b,c] = [1,[2,3]];
console.log(a,b,c); // 1 [2, 3] undefined

从这里可以看出,结构赋值其实就是一种模式匹配,两边模式要一致才行。

3. 字符串解构

字符串也可以这么玩,因为字符串的字符也是有索引的。在解构赋值的过程中,字符串被转换成了一个类似数组的对象。

// 证明字符串有索引
let str = "hello";
console.info( str[0] );  // h
console.info( str[1] );  // e
// 字符串解构
let str = "hello";
let [a,b, , ,c] = str ;
console.info( a,b,c);  // h e o

4. 拓展运算符(...)

也称为扩展运算符 ,就是三个连续的点(...)。

作用:取出参数对象中可遍历的属性,拷贝到当前对象之中。(百度出来的)

我的个人理解是:可以把数组转为数据序列。

  • 函数参数

function add(x, y) {   // 参数 x,y 是个数据序列,逗号隔开。
  return x + y;
}

let numbers = [4, 10]; // 数组
add(...numbers); // 14。 把数组转为数据序列,可以作为函数的参数。
  • 复制数组
// 复制数组
let arr1 = [1, 2];
let arr2 = arr1;   // 数组是引用数据类型。arr1,arr2 都指向同一个数组空间。
					 // 一个数据改了,另一个数据也改了
arr2[0] = 2;
console.info(arr1) // [2, 2]  ,复制失败

// 用 ... 拓展运算符就可以复制数组
let arr1 = [1, 2];
let arr2 = [...arr1];
arr2[0] = 2 ;
console.info( arr1 );  // [1, 2]  ,复制成功。arr1 不受 arr2 数据变化影响。
  • 数组合并
// 传统做法
let arr = [1,2,3];
let newarr = [4, 5].concat(arr); // 用concat连接两个数组,返回一个新的数组副本

// ES6 拓展运算符
let arr = [1,2,3];
let newArr1 = [4, 5,...arr];
let newArr2 = [4, ...arr , 5];
console.info( newArr1 );  // [4, 5, 1, 2, 3]
console.info( newArr2 );  // [4, 1, 2, 3, 5]
  • 与数组结构一起用

用于生成数组

let [first, ...rest] = [1, 2, 3, 4, 5];
console.info( first ); // 1
console.info( rest  ); // [2, 3, 4, 5]

如果将扩展运算符用于数组赋值,只能放在参数的最后一位,否则会报错。

let [...rest, last] = [1, 2, 3, 4, 5];
// 报错
let [first, ...rest, last] = [1, 2, 3, 4, 5];
// 报错
  • 将字符串转为真正的数组
let str = "hello";
let arr = [...str];
console.info( arr );  // ["h", "e", "l", "l", "o"]

三、对象解构

按照属性来进行解构赋值,如果解构不成功,变量的值等于 undefined对象解构可以指定默认值。

1. 和数组解构的对比

  • 数组的元素是按次序排列的,变量的取值由它的位置决定;

  • 模式匹配,两边都必须是 Object 对象

  • 而对象的属性没有次序,变量必须与属性同名,才能取到正确的值。

// 对象的解构赋值,跟顺序没有关系
let {age, name } = { name:"Tom", age:18 };
console.info(age,name);  // 18 , Tom

let { age:b, name:a } = { nam e:"Tom", age:18 };
console.info( b, a );    // 18 , Tom

左右属性名不一致,会得到 undefined。

let {age, nameZ } = { name:"Tom", age:18 };
console.info(age,nameZ);  // 18 , undefined

let { age:b, nameZ:a } = { name:"Tom", age:18 };
console.info( b, a );    // 18 , undefined

对象解构语句不是以变量声明关键字(如var,let或const)开头,则需要将语句包裹在括号中。 否则会报错。

 ({ a, b } = { a:100, b:200 }  ); // good
let { a, b } = { a:100, b:200 } ; // good

let  a , b ;
{ a, b } = { a:100, b:200 } ;   // 报错

2. 对象解构默认值

// 变量的非 undefined 的值可以取到
let { name, age = 28 } = { name:"Tom", age:18 };
console.info( name, age );    // Tom , 18

// 变量取到了 undefined ,则返回默认值
let { name, age = 28 } = { name:"Tom" };
console.info( name, age );    // Tom , 28
let {name: a = "Tom", age: b = 28} = { name :"Lily"};
console.info( a, b );   // Lily, 28

// 右侧一个值都没有
let {name: a = "Tom", age: b = 28} = {};
console.info( a, b );   // Tom, 28

3. 对象作为函数参数

Object 对象可以作为函数参数。

let  addFun = function( obj ){
    let sum = obj.a + obj.b ;
    console.info( sum );
};
addFun({
    a:100,
    b:200
});  // 300 

为了设置 a ,b 默认值。利用对象解构,设置形参

// 实参和形参会进行解构操作。
let  addFun = function( { a=100, b=100 } ){
    let sum = a + b ;
    console.info( sum );
};
addFun({
    a:100,
    b:200
});  // 300。a ,100 ; b,200

addFun({ a:50 });  // 150。a,50; b 被省略,取默认值 100 。
addFun({ });  // 200。a , b 均取默认值
addFun(); // Cannot read property 'a' of undefined

上面代码只使用了对象的解构赋值默认值,没有使用函数参数的默认值。只有当函数 addFun 的参数是一个对象时,变量 a 和 b 才会通过解构赋值生成。

如果函数 addFun 调用时没提供参数,变量 a 和 b 就不会生成,从而报错。

addFun();  // 报错。Uncaught TypeError: Cannot read property 'a' of undefined

相当于在执行代码

{ a=100, b=100 } = undefined ; 

试图对 undefined 进行对象结构,会报错。

通过提供函数参数的默认值,就可以避免这种情况。

let  addFun = function( { a=100, b=100 } = {} ){
    let sum = a + b ;
    console.info( sum );
}; 
addFun( );  // 200。

参数默认值是 {} 。{} 会解构给 a,b 赋值。a,b 解构的值都是 undefined,所以取 a,b 均会获取解构的默认值 100。

四、对非对象进行解构

如果解构的值为 null、undefined,会得到一个类型错误提示。

如果你的值为数字、布尔值、字符串,会得到一个 undefined。

如果等号左侧的变量名为 Object.prototype 上的方法名称时,返回的就是方法实例。

let {a} = null ;   // 报错
let {a} = undefined ;   // 报错
let { age:a } = undefined ;   // 报错

let {a} = 13 ;   // a = undefined

let { toString } = 123 ;  // toString() { [native code] }

猜你喜欢

转载自blog.csdn.net/weixin_42703239/article/details/106290444