Skip to content

一次搞懂ES的解构赋值

解构赋值的类别

数组的解构赋值

  1. 数组的解构规则,根据下标进行,将对应下标的值赋给对应下标的变量。
    js
        let [index1,index2,index3] = [1,2,3];
        console.log(index1,index2,index3) //1 2 3
    可以间断,通过空占位。
    js
        let [index1,,index3] = [1,2,3];
        console.log(index1,index3) //1  3
  2. 使用...扩展运算符获取未接受的变量。
    js
        let [index1,,...rest] = [1,2,3];
        console.log(index1,rest) //1. 关于解构赋值.html:11 1 [3]
    占位仍然算接受变量,在数组中,扩展运算符会将从第一个未匹配到对应下标变量的数据到末尾接收存放在一个数组中。

特别注意,扩展运算符只能在末尾 js let [index1,index2,index3,...rest] = [1,2,3]; console.log(index1,rest) //1 [] 如果所有数据都有对应下标的变量接收,那么rest为空数组。

  1. 可以直接赋值给变量的属性:
    js
        let obj = {
    
            },
            arr = [];
        [
            obj.a,
            arr[0]
        ] = [1, 2];
        console.log(obj, arr) //{a: 1} [2]
    需要注意的是,因为是赋值给已经声明的变量的属性,所以不需要加声明命令并且同样支持赋初始值。
  2. 赋初值
    js
        let [
            index1 = 4,
            index2 = 5,
            index3 = 6,
            index4 = 7,
            index5 = 8,
            index6 = 9,
            ...rest
        ] = [0, '', null, false, , undefined];
        console.log(index1, index2, index3, index4, index5, index6, rest) // 0 "" null false 8 9 []
    因为数组中[,]某个下标没有键入内容默认赋值为undefined[,][0] == undefined为true,访问不存在的下标也会返回undefined。 所以在数组解构赋值过程中,只有对应下标的值为undefined的情况下,对应变量才会使用自己的初始值。 类似如:
    js
        for(let i = 0 ; i < target.length ; i++){
            if(target[i] === 'undefined){
                r[i] =  r[i]
            }else{
                r[i] = target[i]
            }
        }
    初值可以是任何类型:
    js
        let [
            index1 = 1,
            index2 = "2",
            index3 = true,
            index4 = undefined,
            index5 = null,
            index6 = {a:1},
            index7 = [],
            index8 = ()=>{}
        ] = [];
        console.log(index1, index2, index3, index4, index5, index6, index7, index8) // 1 "2" true undefined null {a: 1} [] ()=>{}

对象的解构赋值

  1. 对象的解构赋值规则:通过对象的键进行匹配,将匹配到对应键的值赋给变量(value变量是声明的)。

    js
        let {
            key2:value
        } = {
            key1:"realvalue1",
            key2:"realvalue2"
        }
        console.log(value) // realvalue2

    因为是通过键进行匹配的,所以同一个变量可以被多个变量接收:

    js
        let {
            key2:value1,
            key2:value2,
        } = {
            key1:"realvalue1",
            key2:"realvalue2"
        }
        let {
            key2:value1,
            key2:value2,
        } = {
            key1:"realvalue1",
            key2:{
                realvalue2:"realvalue2"
            }
        }
        console.log(value1) // {realvalue2: "realvalue2"}
        console.log(value2) // {realvalue2: "realvalue2"}
        console.log(value1 === value2) // true

    这里将键key2的值换成对象,只是想表达key2对应的变量赋值的都是key2对应的数据,因为{} != {},利用这一点并且value1 = value2,所以赋予的是同一个值(因为对象赋值是存储地址,所以才能相等)

  2. 赋值支持es6简写 因为es6中对象的属性支持简写,即:

    js
        let a = {
            name
        }
        // 写法等价于
    
        let a = {
            name:name
        }

    所以以上如果使用同名变量接收可以使用简写:

    js
        let {
            key2
        } = {
            key1:"realvalue1",
            key2:"realvalue2"
        }
        console.log(key2) // realvalue2
  3. 使用扩展运算符...接收未被匹配到键的值:

    js
        let {
            key2 ,
            ...rest
        } = {
            key1:"realvalue1",
            key2:"realvalue2"
        }
        console.log(rest) // {key1: "realvalue1"}

    对象解构中,...接收未被匹配的键值对存放在对象rest中,如果全部key都被匹配过(>=1)一次,rest为{}

  4. 可以直接赋给变量的属性:

    js
        let obj = {
                key: ""
            },
            arr = [];
        ({
            key1: obj.key,
            key2: arr[0]
        } = {
            key1: "realvalue1",
            key2: "realvalue2"
        })
        console.log(obj, arr) // {key: "realvalue1"} ["realvalue2"]

    需要注意的是,对象的解构直接赋给变量的时候,需要用小括号括起来,原因js中{}如果没有命令修饰,会被认为是代码块而不是一个对象,执行内部的内容从而产生错误,所以这种情况需要使用小括号将其转化为一个表达式。 其他的情况下的小括号:

    于编译器来说,一个式子到底是模式,还是表达式,没有办法从一开始就知道,必须解析到(或解析不到)等号才能知道。ES6 的规则是,只要有可能导致解构的歧义,就不得使用圆括号。 简单来说两周情况不能使用: 声明语句中(即变量未先定义,解构的时候同时声明+赋值),不使用括号: 以下错误示例: ```js let [(a)] = [1]; let ([(a)]) = [1];

     let {x: (c)} = {};
     let {(x): c} = {};
     let {(x: c)} = {};
     let ({x: c}) = {};
     ```
     函数参数也属于变量声明,因此也不能有圆括号。
    

    模式匹配的部分不能使用括号(数组中的位置和对象的key): - 对象解构中的key {(key):value} = { key:'value' } - 对象解构中简写的变量 {(key)} = { key:'value' }

  5. 赋初值

    js
        let {
            key1:value1 = "哈哈",
            key2:value2 = "呵呵",
            key3:value3 = "喀喀"
    
        } = {
            key1:1,
            key3:undefined,
        }
        console.log(value1,value2,value3) // 1 "呵呵" "喀喀"

    和数组一样,支持所有类型的初始值,并且只有在对应键不存在或者值为undefined的时候使用初始值。

混合解构

对对象嵌套数组或者数组嵌套对象进行解构,按照对象或者数组的规则一层一层的进行解构即可,嵌套的部分是由上一次解构出的解构进行再次解构。

js
    let {
        p:[index]
    } = {
        p:[1]
    }
    // 第一步: [index]  = [1]
    // 第二步:index = 1

使用场景

  • 模块导入
js
// ES6 模块
import {stat,exists,readFile} from 'fs'

// CommonJS 模块
let {stat,exists,readFile} = require('fs');
  • 函数参数 通常对于一个有默认值的参数,我们是这么处理的:
js
    function test(opts){
        var id = opts && opts.id || 1;
        var name = opts && opts.name || 'jack';
        console.log(id,name)
    }

    test();

使用解构赋值:

js
    function test({
        id = 1,
        name = 'jack'
    } = {}) {
        console.log(id, name)
    }
    test()

这里进行了两次解构设置默认值:第一次将{}赋给第一个参数当默认值,避免调取的时候没有传入形参导致第二次解构报错;第二次对第一个参数进行解构,并设置idname属性的初始值。