首页 > 代码库 > ES6(变量的解构赋值)

ES6(变量的解构赋值)

     以前给变量赋值都是var a = 10这样直接赋值,如今ES6提供了一种方法来赋值,即解构赋值,解构赋值是通过按照一定的模式,从数组和对象里读取值,然后对变量赋值变量的解构赋值包括:数组,对象,字符串,数值,布尔值,函数参数。

      【1】数组的解构赋值

var  [a , b , c] = [1 , 2 , 3];

      在ES6中可以直接这么对变量赋值,这种写法被称为“模式匹配”,只要两边的模式一样就可以进行赋值。例如:

let  [a,[b,c]] = [1,[2,3]];    //  a = 1  // b =  2    // c = 3
let [ , , c] = [1,2,3];    //  c = 3
let  [a, , c]  = [1,2,3];  // a  = 1  c  =  3
let  [a,...b] = [1,2,3];  // a = 1   ...b =  [2,3]
let  [a,b,...c] = [1];  //a = 1  b = undefined   ...c = []

     上面最后一个赋值,b的值为undefined,这就是解构不成功的结果。

     如果等号的右边不是数组,那么将会报错,譬如:

let [a] = 1;
let [a] = false;
let [a] = undefined;
let [a] = null;
let [a] = NaN;
let [a] = {};

    会报错是因为右边的值转为对象后不具有Iterator接口(前五个例子),还有本身就不具有Iterator接口(最后一个例子)。这说明了只要某种数据结构具有Iterator接口,都可以使用数组形式进行解构赋值。

    解构赋值允许指定默认值,不过需要注意的是,只有变量严格等于undefined,默认值才会生效。比如:

var  [x = 1] = [undefined];  // x =1
var  [x = 1] = [null];  // x = null

    如果默认值是一个表达式的话,只有在变量取不到值时才会执行这个表达式。

    默认值还可以引用解构赋值的其他变量,不过前提是,这个被引用的变量必须已经声明了,不然会报错,比如:

let  [x = 1, y = x] = []; // x =1  y =1
let  [x = 1, y = x] = [2]; // x = 2 y = 2
let  [x = 1, y = x] = [1,2] // x = 1 y = 2
let  [x = y, y = 1] = []; //referenceError

   【2】对象的解构赋值

       对象的解构与数组有一个重要的不同。即数组的元素是按次序排列的,变量的取值由它的位置所决定;而对象的属性不需要按次序排列,但需要注意的是,变量必须与属性同名,只有这样才能取到正确的值。比如:

var { bar, foo } = { foo: "aaa", bar: "bbb" }; //  foo = "aaa"   bar = "bbb"
var { baz } = { foo: "aaa", bar: "bbb" }; //  baz = undefined

      如果变量名与属性名不一样,但又想取到值,可以这么写:

var { foo: baz } = { foo: ‘aaa‘, bar: ‘bbb‘ };  // baz = "aaa"   // foo  error: foo is not defined

     通过这个例子,我们可以知道其实真正被赋值的是变量baz,而不是模式foo,也就是说对象的解构赋值的内部机制,是先找到同名属性,然后再赋给对应的变量。不过需要注意的是,采用这种写法时,变量的声明和赋值是一体的,对于let和const来说,变量是不能重新声明的,所以一旦赋值的变量以前声明过,就会报错。例如:

let foo;
let {foo} = {foo: 1}; // SyntaxError: Duplicate declaration "foo"

    不过如果变量是var 声明的就不会出现这个错误,因为var声明的变量允许重复声明,在去掉第二个let 之后就可以成功解构,例如:

let foo;
({foo} = {foo: 1}); //  成功

   但是一定要记得加上(),这个是必须的,因为解析器会将起首的大括号,理解成一个代码块,而不是赋值语句。所以将一个已经声明的变量用于解构赋值就需要添加()。

   解构也可以用于嵌套结构的对象。比如:

var node = {
    loc: {
      start: {
         line: 1,
         column: 5
      }
    }
};
var { loc: { start: { line }} } = node;
line // 1
loc // error: loc is undefined
start // error: start is undefined

    只有line是变量,所以可以被赋值,而loc和start是模式,所以不会被赋值。

    对象的解构也可以指定默认值,和数组一样,默认值生效的前提是,对象的属性值严格等于undefined。

   【3】字符串的解构赋值

         当使用字符串进行解构赋值时,字符串就被转换成了一个类似数组的对象,这个对象有一个length属性,也可以对这个属性解构赋值。比如:

const [a, b, c, d, e] = ‘hello‘; // a = "h"  b = "e"  c = "l"  d = "l"  e = "o"
let {length : len} = ‘hello‘;  // len = 5

   【4】 数值和布尔值的解构赋值

         当解构赋值数值和布尔值时,会先转化为对象。那么从这里我们就知道解构赋值的规则是,只要等号右边的值不是对象,就先将其转为对象。注意undefined和null不能转为对象,所以无法对它们进行解构赋值,不然会报错,例如:

let { prop: x } = undefined; // TypeError
let { prop: y } = null; // TypeError

   【5】 函数参数的解构赋值

            函数的参数不仅可以解构赋值,还可以使用默认值。而且undefined会触发函数参数的默认值。

function move({x = 0, y = 0} = {}) {
      return [x, y];
}
move({x: 3, y: 8});  // [3, 8]
move({x: 3});        // [3, 0]
move({});            // [0, 0]
move();              // [0, 0]

         如果是为函数move的参数指定默认值,而不是为变量x和y指定默认值,那么就会得到不一样的结果,如:

function move({x, y} = { x: 0, y: 0 }) {
return [x, y];
}
move({x: 3, y: 8}); // [3, 8]
move({x: 3}); // [3, undefined]
move({}); // [undefined, undefined]
move(); // [0, 0]

   圆括号问题

       在解构赋值的某些情况下,我们需要使用到圆括号,那么在什么情况下可以用圆括号,什么情况下不能用圆括号。

      可以使用圆括号:[1]: 赋值语句的非模式部分,可以使用圆括号。

      不可以使用圆括号:[1]:变量声明语句中,不能带有圆括号。

                               [2]:函数参数中,模式不能带有圆括号。

                               [3]:赋值语句中,不能将整个模式,或嵌套模式中的一层,放在圆括号之中。

     变量的解构赋值在什么时候用呢——[1]:交换变量的值;

                                                  [2]:从函数返回多个值;

                                                  [3]:函数参数的定义;

                                                  [4]:提取 JSON 数据;

                                                  [5]:函数参数的默认值;

                                                  [6]:遍历 Map 结构;

                                                  [7]:输入模块的指定方法。

 

ES6(变量的解构赋值)