[ES6] 细化ES6之 -- 变量的解构赋值

变量的解构赋值

解构赋值是什么

ES6 允许按照一定模式,从数组和对象中提取值,对变量进行赋值

var/let [变量名称1,变量名称2...] = 数组或对象

本质上,这种写法属于“模式匹配”,只要等号两边的模式相同,左边的变量就会被赋予对应的值

 

解构赋值失败

如果解构不成功,变量的值就等于undefined

解构赋值失败 - 定义变量的数量大于值的数量

let [m,n] = [1];
console.log(m, n);//1 undefined

 

不完全解构赋值

等号左边的模式,只匹配一部分的等号右边的数组

不完全解构赋值 – 定义变量的数量小于值的数量

解构依然可以成功

let [a,b] = [1,2,3];
console.log(a, b);//1 2
默认值

解构赋值允许指定默认值

解构赋值失败时,变量的默认值为undefined
默认值–指的就是在解构赋值失败时,重写undefined默认值

ES6 内部使用严格相等运算符(===),判断一个位置是否有值。所以,只有当一个数组成员严格等于undefined,默认值才会生效

let [a=true] = [100];
console.log(a);//100

let [x, y = 100]= [10];
console.log(x,y);// 10 100

// ES6底层将为变量赋值的值与undefined进行比较(全等于)
let [m,n = 100]=[10,undefined];
console.log(m,n);

 

ES6底层将为变量赋值的值只是与undefined进行比较(null等没有意义的)

let [v,w=100] = [10,null]
console.log(v, w);//10 null

 

对象的解构赋值

解构不仅仅可以用于数组,也可以用于对象

let {x,y}={
    x:10,
    y:20
}
console.log(x, y);//10 20

 

对象的解构赋值

对象的解构与数组有一个重要的不同。数组的元素是按次序排列的,变量的取值由它的位置决定;而对象的属性没有次序,变量必须与属性同名,才能取到正确的值。

  • 数组[] = 对象{}
let [m,n]= {
    m:20,
    n:10
}
console.log(m, n);// {(intermediate value)(intermediate value)} is not iterable
  • 对象{} = 对象{函数}
let {m,n}={
    m:100,
    n:function () {
        return 10;
    }
}
console.log(m, n());// 100 10
  • 数组[] = 数组[函数]
let [m, n] =[100,function(){return 10;}];
console.log(m,n());// 100 10
  • 对象{} = 对象{对象,函数}
let {m,n}={
    m: {
        name:'张无忌'
    },
    n:function () {
        return 10;
    }
}
console.log(m.name,n());// 张无忌 10
  • 数组[] = 数组[对象,函数]
let [m, n] =[{name:'张无忌'},function(){return 10;}];
console.log(n()); // 10
  • 数组[] = 数组[数组]
let [a,b] = [[1,2],3]
console.log(a, b);//[ 1, 2 ] 3
let [[a,b],c] = [[1,2],3]//等价于 let [a,b,c] = [1,2,3]
console.log(a, b, c);// 1 2 3

 

解构赋值失败
let {m,n}={
    m:100
}
console.log(m, n);//100 undefined

如果解构模式是嵌套的对象,而且子对象所在的父属性不存在,那么将会报错

// 报错
let {x: {y}} = {y: '123'};

 

默认值

对象的解构赋值也可以指定默认值。默认值生效的条件是对象的属性值全等于undefined。

let {x,y=1}={
    x:100
}
console.log(x, y);// 100

 

注意点(参考阮一峰的ECMAScript 6 入门)
  • 如果要将一个已经声明的变量用于解构赋值,必须非常小心。
// 错误的写法
let x;
{x} = {x: 1};
console.log(x)

// 正确的写法
let x;
({x} = {x: 1});
console.log(x)

因为 JavaScript 引擎会将{x}理解成一个代码块,从而发生语法错误。只有不将大括号写在行首,避免 JavaScript 将其解释为代码块,才能解决这个问题。

  • 解构赋值允许等号左边的模式之中,不放置任何变量名。因此,可以写出非常古怪的赋值表达式
({} = [true, false]);
({} = 'abc');
({} = []);
  • 由于数组本质是特殊的对象,因此可以对数组进行对象属性的解构。
let arr = [1, 2, 3];
let {0 : first, [arr.length - 1] : last} = arr;
console.log(first, last);// 1 3

数组arr0键对应的值是1[arr.length - 1]就是2键,对应的值是3

 

字符串的解构赋值

字符串被转换成了一个类似数组的对象

let  [a,b,c]="xyz"
console.log(a, b, c);// x y z

let  [a,b,c]="xxyyzz"
console.log(a, b, c);// x x y

let  [a,b,c]="大前端了"
console.log(a, b, c);// 大 前 端

 

数值与布尔值的解构赋值

解构赋值时,如果等号右边是数值和布尔值,则会先转为对象.

规则:

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

let num = new Number(100);
console.log(num.toString());// 100

//数字值或布尔值的解构赋值 - 先将数字值或布尔值转换成对象类型
let{toString:m}=100;//100本身就是number类型对象
console.log(m)// [Function: toString]

let  {toString:x}=true;
console.log(x === Boolean.prototype.toString());//true

 

函数参数的解构赋值

函数参数的解构赋值
//函数定义 – 形参,相当于在函教作用域中定义了一个局部变量(没有赋值)
function fn(a,b) {
    console.log(a, b);//10 20
}
//函数调用 – 实参,相当于在函数作用域中为定义的变量进行赋值
fn(10,20)

形参传入什么格式在实参用相同的格式进行匹配

 

默认值
function move({x = 0, y = 0} = {}) {
    return [x, y];
}

console.log(move({x: 3, y: 8})); // [3, 8]
console.log(move({x: 3})); // [3, 0]
console.log(move({})); // [0, 0]
console.log(move()); // [0, 0]

 

小括号的问题

小括号的问题

解构赋值虽然很方便,但是解析起来并不容易。对于编译器来说,一个式子到底是模式,还是表达式,没有办法从一开始就知道,必须解析到(或解析不到)等号才能知道。

由此带来的问题是,如果模式中出现圆括号怎么处理。ES6 的规则是,只要有可能导致解构的歧义,就不得使用圆括号。

但是,这条规则实际上不那么容易辨别,处理起来相当麻烦。因此,建议只要有可能,就不要在模式中放置圆括号。

 

不能使用小括号的情况
  • 变量声明语句
// 全部报错
let [(a)] = [1];

let {x: (c)} = {};
let ({x: c}) = {};
let {(x: c)} = {};
let {(x): c} = {};

let { o: ({ p: p }) } = { o: { p: 2 } };

 

  • 函数参数

函数参数也属于变量声明,因此不能带有圆括号

// 报错
function f([(z)]) { return z; }
// 报错
function f([z,(x)]) { return x; }

 

  • 赋值语句的模式
// 全部报错
({ p: a }) = { p: 42 };
([a]) = [5];

 

可以使用它小括号的情况

赋值语句的非模式部分,可以使用小括号

[(b)] = [3]; // 正确
({ p: (d) } = {}); // 正确
[(parseInt.prop)] = [3]; // 正确

 

解构赋值的用途

  • 交换变量的值

解构赋值可用于两个变量之间交换值。

let x = 1;
let y = 2;
[x, y] = [y, x];
console.log(x, y);// 2 1

 

  • 从函数返回多个值

    函数只能返回一个值,如果要返回多个值,只能将它们放在数组或对象里返回。如果使用解构赋值的话,很容易实现函数返回多个值

    • 返回一个数组
    function fn() {
        return [1, 2, 3];
    }
    let [a, b, c] = fn();
    console.log(a, b, c);// 1 2 3
    
    • 返回一个对象
    function fn1() {
        return {
            a1: 1,
            b2: 2
        };
    }
    let { a1, b2 } = fn1();
    console.log(a1, b2);// 1 2
    

     

  • 函数参数的定义

    解构赋值可以方便地将一组参数与变量名对应起来。

    • 参数是一组有次序的值
    function f([a, b, c]) {
        console.log(a, b, c); // 1 2 3
    }
    f([1, 2, 3]);
    
    • 参数是一组无次序的值
    function f({q, w, e}) {
        console.log(q, w, e); // 3 2 1
    }
    f({e:1, w:2, q:3});
    

     

  • 函数参数的默认值

jQuery.ajax = function (url, {
  async = true,
  beforeSend = function () {},
  cache = true,
  complete = function () {},
  crossDomain = false,
  global = true,
  // ... more config
} = {}) {
  // ... do stuff
};

指定参数的默认值,就避免了在函数体内部再写var foo = config.foo || 'default foo';这样的语句。

 

  • 提取JSON数据

解构赋值对于提取JSON对象中的数据内容尤其有用。

let jsonData = {
  name: "张无忌",
  age: 11,
  job: "教主"
};

let { name, age, job } = jsonData;

console.log(name, age, job);
// 张无忌 11 教主

 

©️2020 CSDN 皮肤主题: 像素格子 设计师:CSDN官方博客 返回首页