变量的解构赋值

结构赋值是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); //1
console.log(bar); //2
console.log(baz); //3
//例二
let [,,third] = ["dog","pig","lion"];
console.log(third); //lion
//例三
let [x,,y] = [1,2,3];
console.log(x); //1
console.log(y); //3
//例四
let [tail,...head] = [1,2,3,4,5]; //  ...是扩展符的意思
console.log(tail); //1
console.log(head); //[2,3,4,5]

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

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

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

let [a,[b],c] = [1,[2,3],4];
console.log(a); //1
console.log(b); //2
console.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); //lion
console.log(x+y); // pig+mouse;
console.log(a); //dog
console.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); //lion
console.log(bar); //mouse

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

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

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

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

let 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); //lion
console.log(bar); //mouse

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

var {foo:baz} = {bar:"mouse",foo:"lion"};
console.log(baz); //lion
console.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); //hello
console.log(y); // world
console.log(line); // lion
console.log(loc); // loc is not undefined
console.log(start); // start is not undefined

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

3.字符串的解构赋值

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

const [a,b,c,d,e] = "lion!";
console.log(a); //l
console.log(b); //i
console.log(c); //o
console.log(d); //n
console.log(e); //!

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

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

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

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

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

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

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

let {lion:x} = undefined;
let {mouse:y} = null;
console.log(x); //TypeError
console.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
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值