侧边栏壁纸

JavaScript中变量的结构赋值

2022年12月15日 850阅读 0评论 0点赞

1.数组的解构赋值

基本用法:

  • ES6允许按照一定模式从对象和数组中提取值,然后对变量进行赋值,称为解构;
  • 数组解构赋值本质上是一种模式匹配,只要等号两边的模式相同,左边的变量就会被赋予对应的值;

    <script>
      let [a,b,c] = [1,2,3];
      console.log(a,b,c); // 1 2 3
      
      // 只要等号两边的模式匹配,就能完成解构赋值
      let [, , third] = ["aa","bb","cc"];
      console.log(third);// cc
      
      let [one,[two,[three]]] = [1,[2,[3]]];
      console.log(one,two,three);
    </script>
  • 如果==解构不成功==,变量的值为undefined;
  • ==不完全解构==:等号左边的模式只能匹配一部分等号右边的数组,此时依然能够解构成功;
// 不完全解构
let [aaa,bbb] = [111,222,333];
console.log(aaa,bbb); // 111 222
  • 如果==等号右边不是数组(严格来说是不可遍历的结构),将会报错==,如1、false、NaN、null、undefined、{},这些值转换为对象以后不具备Iterator接口(前5个),或者本身就不具备遍历器(最后一个);
  • 结合上一条,也可以认为==只要是具有Iterator接口的数据结构,都可以采用数组形式解构赋值==;

默认值:

  • 解构赋值允许设置默认值:在等号右边能匹配到值的前提下,默认值无效;

    // 解构赋值的默认值设置
    let [d = 1] = [];
    console.log(d);// 1
    
    let [x = 1] = [undefined];
    x // 1
    
    let [x = 1] = [null];// null 不全等与undefined
    x // null
  • ES6内部用全等判断一个位置是否有效,因此==如果一个数组成员如果不是全等于undefined,默认值是无效的==;
  • 如果一个==默认值是一个表达式==,==那么该表达式是惰性求值的,即只有在用到默认值时才会求值==;

    //默认值为表达式时,表达式只有在用到时才会求值
    let [a = fn()] = [];
    let [b = fn()] = [222];
    function fn(){
      return 1;
    }
    console.log(a,b); // 1 222
  • ==默认值还可以是等于一个其他变量,前提是该变量必须已经声明==;
// 默认值也可以是其他变量(该变量需要已经被声明)
let [x = 1 , y = x] = [];
console.log(x,y);// 1 1
let [w = z , z = 1] = []
console.log(w); // 报错,z还未声明

2.对象的解构赋值

  • 对象解构与数组解构有一个重要不同:==数组中的元素是按次序排列的(变量取值由位置决定)==,但是==对象的属性是无序的,要赋值的变量需要跟属性同名才能取到正确的值==;
  • 对象解构赋值的==内部机制是先找到同名属性,然后再赋值给相应地变量,真正被赋值的是后者==;
  • 常见的两种情况:

    • 变量名等于对象中的属性名;
    • 变量名不等于对象中的属性名;
// 1.变量名等于属性名:
let { a  , b } = {a :1 , b : 2};
console.log(a,b); // 1 2

// 2.变量名 !== 属性名
let{first : f , last : l} = {first : 3 , last : 4};
console.log(f,l); // 3 4
  • 与数组一样,对象解构也可以嵌套使用;
// 可以嵌套使用
let obj = {
    p : [
        "hello",
        { y : "world"}
    ]
}
let { p : [x,{y}]} = obj;
console.log(x + y); // helloworld
  • 可以设置默认值,生效的前提是对象的属性值严格等于undefined;
// 可以使用默认值,默认值生效的前提是对象的属性全等于undefined
let {q,w = 1} = {q : 11 , w : undefined};
console.log(q,w); // 11  1  w严格等于undefined,因此默认值等于1
  • 解构赋值允许左边的模式之中不放置任何变量名;
  • 对象解构可以很方便的将现有对象的某个方法赋值给变量;
// 对象解构可以很方便的将现有对象的某个方法赋值给变量
let {random,floor} = Math;
console.log(random);// ƒ random() { [native code] }
  • 数组本质是特殊的对象,因此可以对数组进行对象属性的解构;
// 数组本质是特殊的对象,因此可以对数组进行对象属性的解构
const arr = [1,2,3,4,5,6];
let {0 : first , [arr.length - 1] : last} = arr;
console.log(first,last);// 1 6

3.字符串的解构赋值

  • 字符串也可以解构赋值,此时字符串被转换成一个类似数组的对象(伪数组);
const str = "hello";
let [a,b,c,d,e] = str;  // 此时该字符串被转化成一个伪数组,具有length属性但是没有数组的方法
console.log(a,b,c,d,e); // h e l l o

4.数值和布尔值的解构赋值

  • 在使用数值和布尔值进行解构赋值时,==数值(\==>Number)和布尔值(\==>Boolean)会先转换成对象==;
  • 解构赋值的规则是:==只要等号右边的值不是数组或对象,会先将其转换成对象==;
  • undefined和null无法转换成对象,所以不能对他们进行解构赋值;
// 数值和布尔值,会先被转换成对象再进行赋值
let {toString : s} = 1;
let {toString : b} = true;
// 判断s和b的toString的值是否等于对象的toString方法
console.log(s === Number.prototype.toString); // true
console.log(b === Boolean.prototype.toString); // true

5.函数参数的解构赋值

  • 函数参数也能使用解构赋值;
  • 函数参数解构能使用默认值(同样,undefined值能触发默认值);
// 函数参数使用解构赋值
    function add([x,y]) {
        console.log(x + y);
    }
    add([1,2]); // 3

    let res = [[1,2],[3,4]].map(([a,b]) => a + b);  // map遍历数组,并返回回调函数处理结果组成的新数组
    console.log(res);//[3,7]

    // 可以使用默认值
    function move({x = 0,y = 0}) {
        return [x,y];
    }
    let res1 = move({x : 1 , y : 2});
    let res2 = move({x : 1 });
    let res3 = move({});
    console.log(res1); // [1, 2]
    console.log(res2); // [1, 0]
    console.log(res3); // [0,0]

6.圆括号问题

  • 对于编译器而言,如何分别一个式子是表达式还是模式,没有办法在一开始就对此作出判断,只有在解析到(或解析不到)等号时才能确定;
  • 因此,==只要有可能引起解构歧义,就不要使用圆括号==;
  • 建议:只要有可能,就不要在模式中使用圆括号
  • ==简单来说,只要是将模式放到圆括号中,都是非法的==;

不能使用圆括号的情况:

  • 变量声明语句:
// 1.变量声明语句不能使用圆括号
    let [(a)] = 1;
    let {(a) : 1} = {};
  • 函数参数(也属于变量声明):
// 2.函数参数
    function test([(a)]) {
        // 哈哈哈哈哈
    }
  • 赋值语句的模式:
// 3.赋值语句中的模式
    ({ p : a })= { p :44};

可以使用圆括号的情况:

  • 赋值语句的非模式部分可以使用圆括号:
// 赋值语句的非模式部分可以使用圆括号
    [(a)] = [3];
    console.log(a); // 3

    ({p : (b)} = {p : 4});
    console.log(b);// 4

7.用途

  • 交换变量的值:
// 1. 交换变量值
let a = 1;
let b = 2;
[a,b] = [b,a];
console.log(a,b); // 2 1
  • 从函数返回多个值:
// 2. 从函数返回多个值,以数组为例(对象也同理)
function test() {
    return [1,2,3];
}
let [c,d,e] = test();
console.log(c,d,e); // 1 2 3
  • 定义函数参数:
// 3.定义函数参数
// 3.1 函数参数为有次序的值时,使用数组解构赋值
function fn1([g,h]) {
    console.log(g,h);
}
fn1([1,2]); // 1 2

// 3.1 函数参数为无次序的值时,使用对象解构赋值
function fn2({one : name , two : age}) {
    console.log(name,age);
}
fn2({one : "peanut",two : 88}); // peanut 88
  • 提取JSON数据:
// 4. 提取json数据
let jsonData = {
    name : "peanut",
    age : 33,
    learning : ['javascript','less']
}
// 数组解构赋值
let {name,age,learning : subject} = jsonData;
console.log(name,age,subject);
  • 设置函数参数默认值:
    比如设置jQuery中ajax方法的参数默认值;
  • 遍历map结构
// 5.遍历Map结构
// 5.1 获取对象的键 值
let map = new Map();
// 设置map对象的属性
map.set("first","peanut");
map.set("second","test");
for(let [key,value] of map) {
    console.log(key + " " + value);
}
// first peanut
// second test

// 只获取键
for(let [key] of map){
    console.log(key);
}
// first
// second

// 只获取值
for(let [,value] of map){
    console.log(value);
}
// peanut
// test
  • 输入模块指定的方法
// 输入模块的指定方法
const { SourceMapConsumer, SourceNode } = require("source-map");
0

—— 评论区 ——

昵称
邮箱
网址
取消
博主栏壁纸
14 文章数
18 标签数
10 评论量
人生倒计时
舔狗日记