# 2、变量的解构赋值

从数组和对象中提取值,对变量进行赋值,这被称为解构

# 1、数组的解构赋值

  • 变量赋值

    // before
    let a = 1;
    let b =2;
    let c = 3;
    // Es6
    let [a,b,c] = [1,2,3];
    // 不完全解构
    let [x,y] = [1,2,3,4]   // x = 1 ; y =2;
    // 解构不到的undefined
    let [n,m] = [1]  // n =1 ; m = undefined;
    // 左右结构不一致会报错, 因为转化为对象没有Iterator接口
    let [foo] = null;
    let [foo] = {};  // 本身不具备Iterator接口
    // 对于 Set 结构,也可以使用数组的解构赋值。
    利用new Set数据去重
    let [...arr] = new Set([1,2,3,4,4,4,4])  // arr = [1,2,3,4]
    // 交换变量
    let [A,B] = [1,2]
    [B,A] = [A,B]  // A=2,b=1
    
  • 设置数组变量的默认值

    // 要满足完全等于undefined,默认值才有效
    let [a=2,b=1] = [undefined ,null];  // a=2;b=null
    
    // 惰性求值,只有匹配符合undefined的时候,才去调用函数求值
    let [ a = foo() ] = [2];
    =>
    let a;
    if([2][0]===undefined){
        foo()
    }else{
        a = [2][0]
    }
    // 默认值可以引用解构赋值的其他变量,但该变量必须已经声明。
    let [x = 1,y=x] = [];  // 不会报错
    let [x = y,y=1] = []; // x赋值y时,y还没有被声明
    

# 2、对象的解构赋值

  • 基本用法

    let { x, y, z } = { x: 1, y: "2", z: 3 }; // x=1;y='2';z=3
    
  • 对象的解构与数组有一个重要的不同。数组的元素是按次序排列的,变量的取值由它的位置决定;而对象的属性没有次序,变量必须与属性同名,才能取到正确的值。

    let { boo, foo, coo } = { foo: 112, boo: "233" }; // boo='233'  foo=112  coo=undefined
    
  • 对象的解构赋值,可以很方便地将现有对象的方法,赋值到某个变量。

    let { log, sin, cos } = Math;
    const { log } = console;
    log("hello"); // 'hello'
    
    // 取别名,内部是先召回再赋值 const {log:log} = console; 所以可以取别名代替
    const { log: lg } = console;
    lg("hello"); // 'hello'
    
    // 嵌套的解构赋值一
    let obj = {
      p: ["Hello", { y: "World" }]
    };
    
    let {
      p: [x, { y }]
    } = obj; //  y: 'World'  x:'Hello'
    let {
      p,
      p: [x, { y }]
    } = obj; //  y: 'World'  x:'Hello' p: ["Hello", {y: "World"}]
    
    // 嵌套的解构赋值二
    const node = {
      loc: {
        start: {
          line: 1,
          column: 5
        }
      }
    };
    
    const {
      loc,
      loc: {
        start,
        start: { line, column }
      }
    } = node; // line:1 , column:5
    
    // 嵌套赋值
    let aoo = [];
    let boo = {};
    ({ foo: aoo[0], bor: boo["prop"] } = { foo: true, bar: 123 });
    // aoo= [true]
    // boo={prop:123}
    
  • 设置对象变量的默认值

    默认值生效的条件是,对象的属性值严格等于undefined

    let { x: y = 5 } = { x: 1 }; // y = 1
    let { x: y = 5 } = {}; // y = 5
    var { message: msg = "Something went wrong" } = {}; // msg = 'Something went wrong'
    
    // 注意:对象的解构为了{}不被js引擎理解为代码块,最好用()
    // 正确的写法
    let x;
    ({ x } = { x: 1 });
    
    // 无意义但合法
    ({} = [true, false]);
    ({} = "abc");
    ({} = []);
    
    //由于数组本质是特殊的对象,因此可以对数组进行对象属性的解构。
    let arr = [1, 2, 3];
    let { 0: first, [arr.length - 1]: last } = arr;
    first; // 1
    last; // 3
    

# 3、字符串的解构赋值

  • 字符串解构赋值。字符串被转换成了一个类似数组的对象。

    const [a, b, c] = "Hello"; // a = 'H'   b = 'e'  c ='o'
    
    // 利用这个特点写一个文字乱序
    const Text = "Hello";
    const newT = [...Text].sort(() => Math.random() - 0.5).join();
    
    // 类似数组的对象有length属性,应用解构赋值
    const Text = "Hello";
    const { length: len } = Text;
    len; // 5
    

# 4、数组和布尔的解构赋值

  • 解构赋值的规则是,只要等号右边的值不是对象或数组,就先将其转为对象。由于undefinednull无法转为对象,所以对它们进行解构赋值,都会报错。

    let {proxy:1} = null || undefined  // 报错
    
    // 将等号右边的数字和布尔转化成了对象,将toString属性解构出来
    let {toString: s} = 123;
    s === Number.prototype.toString // true
    let {toString: s} = true;
    s === Boolean.prototype.toString // true
    

# 5、函数的解构赋值

  • 函数的参数也可以使用解构赋值。

    function test([a, b]) {
      return a + b;
    }
    test([1, 2]); // 3
    
    // 数组分批对应 7 无对应, 未加
    [
      [1, 2, 3],
      [4, 5, 6, 7]
    ].map(([a, b, c]) => a + b + c); // [6, 15]
    
  • 函数参数使用默认值

    function move([a = 9, b = 99]) {
      return [a, b];
    }
    
    move([1, 2]); // [1,2]
    move([]); // [9,99]
    move([1]); // [1,99]
    move([undefined, 8]) // [9,8]
      [
        // undefined就会触发函数参数的默认值。
        (1, undefined, 3)
      ].map((x = "yes") => x); // [1,'yes',3]
    

# 6、解构赋值的用途

(1)从函数返回多个值

let [a, b] = ([1, 2][(a, b)] = [2, 1]);
// a = 2 ;  b = 1

(2)接收从函数返回的多个值

函数只能返回一个值,想返回多个需要返回一个对象或数组,用解构赋值取值非常方便
function exam(){
   return [1,2,3]
}
let [a,b,c] = exam()  // a=1;b=2;c=3

function exam(){
   return {foo:'hi',too:'hello'}
}
let {foo:fo , too:to} = exam()  // fo:'hi'  // to:'hello'

(3)函数参数的定义

 利用数组解构的特点,会按顺序匹配
 function test([x,y,z]){ ... }
 test([1,2,3])

 利用对象解构的特点:会自动找key相同的变量值
 function test({x,y,z}){ ... }
 test({x:2,z:3,y:1})

(4)提取 JSON 数据

解构赋值对提取复杂的json数据非常方便;
const JsonData = {
  id: 43,
  status: "OK",
  data: [100, 200]
};
let { id, status, data: dataSource } = JsonData;
console.lgo(id, status, dataSource); // 43,'OK',[100,200]

(5)函数参数的默认值

function test(foo='nihao',too='hi'){
    ...
}
指定函数参数的默认值,当某个参数不传时可以使用默认值代替,不用像之前too||'default too'

(6)遍历 Map 结构

任何部署了 Iterator 接口的对象,都可以用 for...of 循环遍历。Map 结构原生支持 Iterator 接口,配合变量的解构赋值,获取键名和键值就非常方便。

const map = new Map();
map.set('first','Hello')
map.set('second','World')
for([a,b] of map){
    console.log(a + "is" + b )  // first is  Hello   // second is World
}
// 只获取key
for([a] of map) {...}
// 只获取value
for([,b] of map) {...}

(7)输入模块的指定方法

在导入模块时直接将里面的方法解构出来

import { connect } from "dva";

2020-02-24

5:42pm