变量赋值解构
上期我们讲述了let和const相关内容,这期我们接着讲变量解构赋值。
ES6 允许按照⼀定模式,从数组和对象中提取值,对变量进⾏赋值,这被称为 解构(Destructuring)
- 数组的解构赋值
- 对象的解构赋值
- 字符串的解构赋值
- 数值和布尔值的解构赋值
- 函数参数的解构赋值
- 圆括号问题
- ⽤途
1、数组的解构赋值
属于“模式匹配”,只要等号两边的模式相同,左边的变量就会被赋予对应的值。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<script>
let a=10;
let b=20;
let c=30;
console.log(a)//10
console.log(b)//20
console.log(c)//30
let [e,f,g]=[10,20,30];
console.log(e)//10
console.log(f)//20
console.log(g)//30
let [h,[i,j]]=[10,[20,30]];
console.log(h)//10
console.log(i)//20
console.log(j)//30
let [k,,l]=[10,20,30];
console.log(k)//10
console.log(l)//30
let [x1,x2,...xn]=[10,20,30];
console.log(x1)//10
console.log(x2)//20
console.log(xn)//[0,30]
</script>
</body>
</html>
其它数组的结构赋值
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<script>
let[m,n]=[10];
console.log(m)//10
console.log(n)//undefined
let [a,[b,c],d]=[10,[20,30],40]
console.log(a)//10
console.log(b)//20
console.log(c)//30
console.log(d)//40
let [e,[f],g]=[10,[20,30],40]
console.log(e)//10
console.log(f)//20
console.log(g)//40
</script>
</body>
</html>
如果等号的右边不是数组(或者严格地说,不是可遍历的结构(Iterator)),那么将会报错。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<script>
let [a]=1;
let [b]=false;
let [c]=NaN;
let [d]=undefined;
let [e]=null;
let [f]= {};
console.log(a)
console.log(b)
console.log(c)
console.log(d)
console.log(e)
console.log(f)
</script>
</body>
</html>
默认值:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<script>
//当⼀个数组成员严格等于undefined,默认值才会⽣效。
let [b = true] = [];
console.log(b); //true
let [x, y = 'b'] = ['a']; // x='a', y='b'
let [x1, y1 = 'b'] = ['a', undefined]; // x1='a', y1='b'
console.log(x); //a
console.log(y); //b
let [m = 1] = [undefined];
console.log(m) // 1
let [n = 1] = [null]; //值不是undefined,所以没有使⽤默认值
console.log(n) // null
</script>
</body>
</html>
2、对象的解构赋值
解构不仅可以⽤于数组,还可以⽤于对象。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<script>
//对象的解构赋值与数组不同,要求变量必须与属性同名,才能取到正确的值。
//let {name, age} = {name:'张三', age:20};
let {age, name} = {name:'张三', age:20};
let {sex} = {name:'张三', age:20};//解构失败,变量的值等于undefined
console.log(name); //张三
console.log(age); //20
console.log(sex); //undefined
//如果变量名与属性名不⼀致,必须写成下⾯这样
let {email:em, password:ps} = {email:'zs@163.com', password:'123456'};
//如上代码email和password都是匹配的模式,em才是变量。真正被赋值的是变量em,⽽不是模式email
console.log(em); //zs@163.com
console.log(ps); //123456
console.log(email); //错误 ReferenceError: email is not defined
</script>
</body>
</html>
与数组⼀样,解构也可以⽤于嵌套结构的对象。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<script>
//定义⼀个书的信息
var obj = {
book: [
'JavaScript权威指南',
{author:'⼩淘',price:132}
]
};
//let {book:[title, {author, price}]} = obj;
//此时book是模式,不是变量,因此不会被赋值。如果book也要作为变量赋值,可写成如下:
let {book,book:[title, {author, price}]} = obj;
console.log(title); //JavaScript权威指南
console.log(author);//⼩淘
console.log(price); //132
console.log(book); //['JavaScript权威指南',{author:'⼩淘',price:132}]
</script>
</body>
</html>
对象的解构也可以指定默认值
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<script>
var {x=3} = {};
console.log(x); // 3
var {x1, y1=5} = {x1:1};
console.log(x1); // 1
console.log(y1); // 5
var {x2: y2=3} = {};
console.log(y2); // 3
var {x3: y3=3} = {x3: 5};
console.log(y3); // 5
</script>
</body>
</html>
3、字符串的解构赋值
字符串的解构赋值(了解)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<script>
const [a, b, c, d, e] = 'hello';
console.log(a); // "h"
console.log(b); // "e"
console.log(c); // "l"
console.log(d); // "l"
console.log(e); // "o"
</script>
</body>
</html>
类似数组的对象都有⼀个length属性,因此还可以对这个属性解构赋值。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<script>
let {length : len} = 'hello';
console.log(len); // 5
</script>
</body>
</html>
4、数值和布尔值的解构赋值(了解)
解构赋值时,如果等号右边是数值和布尔值,则会先转为对象。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<script>
//解构赋值的规则是,只要等号右边的值不是对象或数组,就先将其转为对象。
let {toString: s1} = 123;
//数值和布尔值的包装对象都有toString属性
console.log(s1 === Number.prototype.toString); // true
let {toString: s2} = true;
console.log(s2 === Boolean.prototype.toString); // true
//由于undefined和null⽆法转为对象,所以对它们进⾏解构赋值,都会报错。
let { prop: x3 } = undefined; // TypeError
let { prop: y3 } = null; // TypeError
</script>
</body>
</html>
5、函数参数的解构赋值
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<script>
//函数的参数也可以使⽤解构赋值。
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]
</script>
</body>
</html>
6、圆括号问题(了解)
变量声明语句,模式不能使⽤圆括号
函数参数也属于变量声明,因此不能带有圆括号
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<script>
// 变量声明语句,模式不能使⽤圆括号,以下6⾏全部报错
// 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];
//将⼀部分模式放在圆括号之中,导致报错
// let[({ p: a }), { x: c }] = [{}, {}];
//可以使⽤圆括号的情况只有⼀种:赋值语句的⾮模式部分,可以使⽤圆括号。
let b,d;
[(b)] = [3]; // 正确 模式是取数组的第⼀个成员跟圆括号⽆关
({p:(d)} = {p:20}); // 正确 模式是p,⽽不是d
[(parseInt.prop)] = [3]; // 正确 与第⼀⾏语句的性质⼀致。
// ⾸先它们都是赋值语句,⽽不是声明语句;其次它们的圆括号都不属于模式的⼀部分
</script>
</body>
</html>
7、用途
交换变量的值
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<script>
let x = 1;
let y = 2;
[x, y] = [y, x];
</script>
</body>
</html>
从函数返回多个值
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<script>
// 函数只能返回⼀个值,如果要返回多个值,只能将它们放在数组或对象⾥返回。
// 有了解构赋值,取出这些值就⾮常⽅便。
// 返回⼀个数组
function example1() {
return [1, 2, 3];
}
let [a, b, c] = example1();
// 返回⼀个对象
function example2() {
return {
foo: 1,
bar: 2
};
}
let { foo, bar } = example2();
</script>
</body>
</html>
函数参数的定义
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<script>
// 解构赋值可以⽅便地将⼀组参数与变量名对应起来
// 参数是⼀组有次序的值
function f([x, y, z]) {}
f([1, 2, 3]);
// 参数是⼀组⽆次序的值
function f({x, y, z}) {}
f({z: 3, y: 2, x: 1});
</script>
</body>
</html>
提取 JSON 数据
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<script>
// 解构赋值对提取 JSON 对象中的数据,尤其有⽤。
let jsonData = {
id: 42,
status: "OK",
data: [867, 5309]
};
let { id, status, data: number } = jsonData;
console.log(id, status, number);
// 42, "OK", [867, 5309]
</script>
</body>
</html>
总结
这里讲解了变量解构赋值的相关内容,我们也有了一定的认识,下一节我们继续讲解ECMAScript6的内容。