ES6标准入门之变量的解构赋值

在正式的讲解以前,咱们先来分析一下,到底什么是解构赋值? 经过对词组的分析,咱们大体能理解,解构---也就是破坏,破坏原来的结构,赋值---固然就是再次赋值。下面咱们来具体的分析一下,到底什么是解构赋值。javascript

数组的解构赋值

1.基本用法

ES6容许按照必定模式从数组和对象中提取值,而后对变量进行赋值,这被称做解构(Destructuring)。 之前,为变量赋值只能直接指定值。java

let a = 1;
let b = 2;
let c = 3;
复制代码

ES6容许写成这样。node

let [a,b,c] = [1,2,3]
复制代码

上面的代码表示,能够从数组中提取值,按照对应的位置进行变量赋值。 本质上,这种写法属于“模式匹配”,只要等号两边的模式相同,左边的变量就会被赋予对应的值。下面是一些使用嵌套数组进行解构的例子。es6

let [foo, [[bar], baz]] = [1,[[2],3]];
 foo //1 ;
 bar //2 ;
 baz //3 ;
 
 let [ , , third] = ["foo", "bar", "baz"];
 third //"baz"
 
 let [x,  , z] = [1,2,3];
 x //1
 z //3
 
 let [head, ...tail] = [1,2,3,4];
 head // 1 
 tail // [2,3,4]
 
 let [x, y, ...z] = ["a"];
 x //"a"
 y // undefined
 z //[] 
复制代码

若是解构不成功,变量的值就等于undefined。json

let [foo] = [];
let [bar, foo] = [1];
复制代码

上面的foo取值都是会等于undefined. 另外一种状况是不彻底解构,即等号左边的模式只匹配一部分等号右边的数组,这种状况,解构依然能够成功。数组

let [x, y] = [1,2,3];
 x //1;
 y //2;
 
 let [a, [b], c] = [1, [1,3], 4];
 a //1
 b //1
 c //4
复制代码

上面的例子属于不彻底解构,可是能够成功。 若是等号的右边不是数组,严格来讲是不可遍历的结构,那么将会报错。数据结构

let [foo] = 1;
let [foo] = false;
let [foo] = undefined;
let [foo] = NaN;
let [foo] = null;
let [foo] = {};
复制代码

上面的语句会报错,由于等号右边的值或者是转换为对象之后不具有Iterator接口,或者自己就不具有Iterator接口。(最后一个表达式) 简单的介绍一下Iterator接口。 遍历器(Iterator)是一种接口,为各类不一样的数据结构提供统一的访问机制,任何数据结构,只要部署Iterator接口,就能够完成遍历操做。 如下数据结构具有原生的Iterator接口。(可以使用for...of方法进行循环遍历)函数

  • Array
  • Map
  • Set
  • String
  • TypedArray
  • 函数的arguments对象
  • NodeList对象

2.Set与Map结构的解构赋值

let [x,y,z] = new Set(["a","b","c"]);
x// "a"
var map = new Map();
map.set("first","hello");
map.set("second","world");
for(let [key, value] of map){
    console.log(key +" is " + value);
}
复制代码

3.默认值

解构赋值容许指定默认值。ui

let [foo = true] = [];
foo //true

let [x,y = 'b'] = ['a'];
x //'a';
y //'b';

let [x, y = 'b'] = ['a', undefined];
x // 'a'
y // 'b'
复制代码

ES6内部使用严格相等运算符(===)判断一个位置是否有值。因此,若是一个数组成员不严格等于undefined,默认值不会生效。spa

let [x = 1] = [undefined];
x // 1
let [x = 1] = [null];
x //null
复制代码

上面的第二个例子没有取到默认值,是由于null不严格等于undefined。 并且,须要注意的是,默认值能够引用解构赋值的其余变量,但该变量必须已经声明。

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
复制代码

最后一个报错,是由于,x用到默认值y时,y尚未声明。

对象的解构赋值

解构赋值不只能够用于数组,还能够用于对象。

let {foo, bar} = {foo:"aaa", bar: "bbb"};
foo // "aaa"
bar // "bbb"
复制代码

与数组的区别

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

let {foo, bar} = {bar: "bbb", foo:"aaa"};
foo // "aaa"
bar // "bbb"
let {baz} = {bar: "bbb", foo:"aaa"};
baz //undefined
复制代码

上面的代码就验证了,取值与次序无关。 第二个例子没有取到值,是由于变量没有对应的同名属性,致使取不到值,最后等于undefined。 若是变量与属性名不一致,必需要写成下面这样,

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

let obj = {first: "hello", last: "world"};
let {firt: f, last: l} = obj;
f // "hello"
l // "world"
复制代码

重点来了,实际上,对象的解构赋值是下面的简写

let {foo: foo, bar: bar} = {foo:"aaa", bar: "bbb"};
复制代码

别名

也就是说,对象的解构赋值的内部机制是先找到同名属性,而后再赋值给对应的变量。真正被赋值的是后者,而不是前者。

let {foo:baz} = {bar: "bbb", foo:"aaa"};
 baz //"aaa"
 foo // foo is not defined
复制代码
上面的代码中,***foo是匹配的模式,baz才是变量。真正被赋值的是变量baz,而不是模式foo。*** 

与数组同样,解构也能够用于对嵌套结构的对象。
复制代码
let obj = {
    p:[
       'hello',
       {y: 'world'}
    ]
 };
  let {p: [x,{y}]} = obj;
  x // "hello"
  y // "world"
复制代码

注意这时,p是模式,不是变量,所以不会被赋值,若是p也要做为变量被赋值,能够写成下面这样,

let obj = {
      p:[
          'hello',
          {y: 'world'}
      ]
   };
  let {p,p: [x,{y}]} = obj;
   x // "hello"
   y // "world"
   p // p:['hello', {y: 'world'}]
复制代码

另外一个例子,

var node = {
     loc:{
         start : {
             line: 1,
             column: 5
         }
     }
  };
 var {loc, loc:{start}, loc:{start: {line}}} = node;
 line // 1
 loc // Object {start : Object }
 start // Object {line: 1, column:5}
复制代码

上面的代码有三次解构赋值,分别是对loc,start,line三个属性的解构赋值。须要注意的是,最后一次对line属性的解构赋值之中,只有line是变量,loc和start都是模式。

对象的变量赋值

若是将一个已声明的变量进行赋值时,必定要当心了!

//错误写法
  let x
  {x} = {x:1};
//syntaxError: syntax error
复制代码

上面的代码会报错,由于JavaScript引擎会将{x}理解成一个代码块,从而发生预发错误。 只要不把{}写在首行,就会解决这个问题。

let {x} = {x:1};
//或者
let x;
({x} = {x:1})
//也能够
{(x) = {x:1}}
复制代码

关于圆括号的使用,保证一个原则,不瞎用。 具体请参考阮一峰大神的es6标准,很全面!总结一下就是,

字符串的解构赋值

例子

const [a,b,c,d,e] = 'hello'
复制代码

数字和布尔类型的解构赋值

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

let {toString : s} = 123;
s === Number.prototype.toString //true
let {toString : s} = true;
s === Boolean.prototype.toString //true
复制代码

上面的代码中,数字和布尔值的包装对象都有toString属性,所以变量s都能取到值。 解构赋值的规则是,只要等号右边的值不是对象或者数组,就先将其转为对象,因为undefined和null没法转换为对象,因此进行解构赋值时会报错。

用途

交换变量的值

//ES5
  var t;
  t = a;
  a = b;
  b = t;

 //ES6
 let x = 1;
 let y = 2;
 [x, y] = [y, x];
复制代码

从函数返回多个值

函数只能返回一个值,若是要返回多个值,只能将他们放在数组或者对象中,有了解构赋值,取出这些值就很方便了。

//返回一个数组
  function example() {
    return [1,2,3,4]
  }
 let [a,b,c,d] = example();
 //若是没有解构赋值,还得循环遍历,分别赋值。
 
 //返回一个对象
  function example() {
    return {
        foo: 1,
        bar: 2
    };
  }
  let {foo, bar} = example();
复制代码

函数参数的定义

解构赋值能够方便地将一组参数与变量对应起来

//参数是一组有次序的值
  function f([x,y,z]) {}
  f([1,2,3])
  //参数是一组有序的值
  function f({x,y,z}) {}
  f({x:1,z:2,x:3});
复制代码

提取JSON中的数据

let jsonData = {
    id:23,
    state:"draft",
    data:{
        name:"hansheng",
        age: 18
    }
 }
 let {id,state,data:info} = jsonData;
  // 23,"draft", {name:"hansheng",age: 18}
复制代码

本文摘录自阮一峰ES6标准入门。

相关文章
相关标签/搜索