变量的解构赋值

来源:互联网 发布:seo转行 编辑:程序博客网 时间:2024/04/30 04:49

结构赋值是ES6中新引进的概念,只要眸中数据结构具有Iterator接口,都可以采用数组形式的解构赋值。

1.数组的解构赋值

基本用法:
ES6允许按照一定得到模式,从数组和对象中提取值,对变量进行赋值,这被称作解构,在这之前,为变量赋值只能通过直接指定值,如下:

var a=0;var b=3;var c=2;

但是,ES6允许这样写:var [a,b,c] = [0,3,2];
上面的代码表示,可以从数组中提取值,按照位置的对应关系对变量赋值。

注意: 这样做的实质其实是“模式匹配”,只要等号两边的模式相同,左边的变量就会被赋予相对应的值,如下例子:

//例一let [foo,[[bar],baz]] = [1,[[2],3]];console.log(foo); //1console.log(bar); //2console.log(baz); //3//例二let [,,third] = ["dog","pig","lion"];console.log(third); //lion//例三let [x,,y] = [1,2,3];console.log(x); //1console.log(y); //3//例四let [tail,...head] = [1,2,3,4,5]; //  ...是扩展符的意思console.log(tail); //1console.log(head); //[2,3,4,5]

下面看看几个结构不成功的例子,一般如果解构不成功,变量的值就会等会undefined,如下:

//例一let [a,b,...c] = ["mouse"];console.log(a); //"mouse"console.log(b); //undefinedconsole.log(c); //[]//例二var [bar] = [];var [baz,foo]=[1];console.log(bar); //undefinedconsole.log(foo); //undefined

还有 种情况是不完全解构,就是说等号左边的模式只匹配到了等号右边数组的 一部分,这种情况下,解构依然是成功的,只是不完全而已,如下:

let [a,[b],c] = [1,[2,3],4];console.log(a); //1console.log(b); //2console.log(c); //4

最后:如果等号右边不是数组,或者说等号左右两边的结构不相同,那么将会报错,下面的例子就会报错:

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

顺便说说:解构赋值不仅适用于var,也适用于let和const。

解构赋值也是允许指定默认值的,如下:

var [foo = "lion"] = [];var [x,y="mouse"] = ["pig"];var [a,b="mouse"] = ["dog",undefined];console.log(foo); //lionconsole.log(x+y); // pig+mouse;console.log(a); //dogconsole.log(b); //mouse

注意: ES6内部使用严格相等运算符(===)判断一个位置是否有值,所以,如果一个数组成员不严格等于undefined,那么解构赋值是不会生效的,如:var [x=1] = [undefined];最后x的值还是1。

如果一个数组成员是null,这事默认值就不会生效,因为null不严格等于undefined。

如果默认值是一个表达式,那么这个表达式是惰性求值的,也就是只有在用到的时候才会求值,如:

function f(){    console.log("aaa");}let [x=f()] = [1];console.log(x); // 1

因为x可以直接取值1,所以就不会执行f()。

2.对象的解构赋值

解构不仅仅可以用在数组还可以用在对象上,如下:

var {foo,bar} = {foo:"lion",bar:"mouse"};console.log(foo); //lionconsole.log(bar); //mouse

这里,对象的解构和数组是不一样的,数组的元素是按次序排列的,变量的取值也是按照位置来决定的,但是对象就不痛,对象的属性是没有次序的,只要变量名与属性同名即可,这样才能取到正确的值,如下:

var {foo,bar,baz} = {bar:"mouse",foo:"lion"};console.log(foo); //lionconsole.log(bar); //mouseconsole.log(baz); //undefined

如果变量名与属性名不同,则必须写成下面这种:

var {foo:baz} = {foo:"lion",bar:"mouse"};console.log(baz); //lionlet obj = {first:'hello',last:'world'};let {first:f,last:l} = obj;console.log(f);console.log(l);

这表明,对象的解构赋值其实是下面这种的简写:

var {foo:foo,bar:bar} = {foo:"lion",bar:"mouse"};console.log(foo); //lionconsole.log(bar); //mouse

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

var {foo:baz} = {bar:"mouse",foo:"lion"};console.log(baz); //lionconsole.log(foo); //error:foo is not defined

注意: 采用这种写法时,变量的声明和赋值是一体的,对于let和const而言,变量不能重复声明,所以一旦赋值的变量,在之前被声明过了,这时就会报错:

let foo;let {foo} = {foo:1};console.log(foo); //SyntaxError:Duplicate declaration "foo"let baz;let{bar:baz} = {bar:1};console.log(bar); //SyntaxError:Duplicate declaration "baz"

这个错误只会出现在let和const中,如果没有第二个let那么就不会报错了。

同样: 对象的解构赋值和数组是一样的,都可以用于嵌套结构,如下:

var obj = {    loc:{        p:[            "hello",            {y:"world"}        ],        start:{            line:"lion",            column:"mouse"        }    }};var {loc:{p:[x,{y}],start:{line}}} = obj;console.log(x); //helloconsole.log(y); // worldconsole.log(line); // lionconsole.log(loc); // loc is not undefinedconsole.log(start); // start is not undefined

上面,只有x ,y ,line 是变量,p ,loc,start 都是模式,是不会被赋值的。
最后:对象的解构也是可以指定默认值的,其用法和数组是一致的。

3.字符串的解构赋值

字符串也是可以解构赋值的,这是因为,此时的字符串被转换成了一个类似数组的对象:

const [a,b,c,d,e] = "lion!";console.log(a); //lconsole.log(b); //iconsole.log(c); //oconsole.log(d); //nconsole.log(e); //!

类似数组的对象,都是有length属性的,因此我们还可以给这个属性解构赋值:

let {length:len} = "lion";console.log(len); // 4

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

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

let {toString:s} = 123;s===Number.prototype.toString //truelet {toString:s} = true;s===Boolean.prototype.toString //true

只要等号右边的值不是对象,就会先将其转换为对象,由于undefined与null都无法转为对象,所以对她们进行解构赋值都是会报错的:

let {lion:x} = undefined;let {mouse:y} = null;console.log(x); //TypeErrorconsole.log(y); //TypeError

5.函数参数的解构赋值

实际上,函数的参数也是可以进行解构赋值的:

function add([x,y]){    return x+y;}var n = add([2,5]);console.log(n); //7

函数参数的解构也是可以使用默认值的:

function move({x=0,y=0} = {}){    return [x,y];}var a= move({x:3,y:8});console.log(a); //[3,8]var b= move({x:3});console.log(b); //[3,0]var c= move({});console.log(c); //[0,0]var d= move();console.log(d); //[0,0]

注意下面的写法是会得到不一样的答案的:

function move({x:0,y:0} = {}){    return [x,y];}var a= move({x:3,y:8});console.log(a); //[3,8]var b= move({x:3});console.log(b); //[3,undefined]var c= move({});console.log(c); //[undefined,undefined]var d= move();console.log(d); //[0,0]

上面的代码是为函数move的参数指定默认值,而不是为变量x,y指定默认值,所以会得到不一样的结果,所以在平常写代码过程中,还是要多多留意下细节,否则,太多的Error会让人很烦恼。

6.用途

说了这么多用法,咱们来看看解构赋值都有什么样的用途,总不能有个理论,却不从使用罢。

  • 交换变量的值:
    交换变量的值用解构赋值是很方便的,如:[x,y] = [y,x];这样的写法不仅简洁,而且语义很清晰。
  • 从函数中返回多个值:
    大家都知道,函数是只能返回一个值的,如果想要返回多个值,就只能将其放在数组或者对象中返回了,挺麻烦!但是有了解构赋值就简单的多了:
//返回一个数组function example(){    return [1,2,3,4];}var [a,b,c,d] = example();//返回一个对象function example(){    return {        foo:"lion",        bar:"mouse"    };}var {foo,bar}= example();
  • 函数参数的定义:
    解构赋值可以方便的将一组参数与变量名对应起来:
//参数是一组有序的值function f([x,y,z]){......}f([1,2,3]);//参数是一组无序的值function f({x,y,z}){......}f({z:4,x:1,y:5});
  • 提取Json数据:
    解构赋值对提取Json对象中的数据尤为重要:
var jsondata = {    id:42,    status:"ok",    data:[11,59]}let {id,status,data:number} = jsondata;console.log(id,status,number);// 42,ok,[11,59]

这样做是可以很快取出Json数据的值的。

  • 遍历Map结构:
    任何部署了Iterator接口的对象,都可以用for…..of循环遍历的,Map结构原生支持Iterator接口,再配合变量的解构赋值,获取键名和键值就非常的方便了:
var map = new Map();map.set("first","lion");map.set("second","mouse");for(let [key,value] of map){    console.log(key+"is"+value);}//first is lion//second is mouse

如果只想取键名则:

var map = new Map();map.set("first","lion");map.set("second","mouse");for(let [key] of map){    console.log(key);}//first//second

如果只想取键值则:

var map = new Map();map.set("first","lion");map.set("second","mouse");for(let [value] of map){    console.log(value);}//lion//mouse
1 0
原创粉丝点击