一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第8天,点击查看活动详情。
六、解构赋值
解构赋值即:解析某一数据的结构,将我们想要的东西提取出来,赋值给变量或常量。
6-1、数组的解构赋值
6-1-1、数组解构赋值的原理
原理:首先进行结构匹配,结构匹配上了后将索引值相同的完成赋值。
const [a, b, c] = [1, 2, 3];
console.log(a,b,c); // 1 2 3
const [a,,c] = [1,[2,3,4,5],6];
console.log(a,c); // 1 6
const [a, [,,,b],c] = [1,[2,3,4,5],6];
console.log(a,b,c); // 1 5 6
可见,首先左右两边结构要对应的上,右边为数组,左边也要为数组解构;然后再与想取的内容的索引对应的上:不想取的内容用逗号隔开即可。
6-1-2、数组解构赋值的默认值
我们先来看以下代码:
const [a,b] = [];
console.log(a, b); // undefined undefined
以上代码相当于:const [a, b] = [undefined, undefined];
如果我们想要在不存在值的时候给默认值如何做呢?
我们可以这样:
const [a = 1,b = 2] = [];
console.log(a, b);// 1 2
我们要注意默认值的生效条件为:只有当一个数组成员严格等于(===)undefined时,对应的默认值才会生效:
const [a = 1,b = 2] = [3, 4];
console.log(a, b); // 3 4 由于对应索引存在值,所以默认值不生效
const [a = 1, b = 2] = [3, null]; // 3 null , null 并不严格等于undefined
const [a = 1, b = 2] = [3]; // 3 2 ,此时b对应的索引值的内容为undefined所以b的默认值生效了
如果默认值时表达式,那么默认值的表达式是惰性求值的:
const fun = () => {
console.log('执行了...');
return 2;
}
const [x = fun()] = [1];
console.log(x); // 1
可见,控制台只输出了1,而没有输出执行了...这句话,这是因为fun没有被真正执行,x对应的索引存在1了,所以不会执行fun,fun的执行是惰性的(用不着默认值,表达式并不会执行;用到的话才会去执行)
6-1-3、数组解构赋值的应用
6-1-3-1、类数组的解构赋值
function a() {
const [a, b] = arguments;
console.log(a, b); // 1 2
}
a(1, 2);
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>数组解构赋值的应用</title>
</head>
<body>
<p>123</p>
<p>321</p>
<p>34567</p>
<script>
// NodeList
const [p1, p2, p3] = document.querySelectorAll('p');
console.log(p1, p2, p3);
</script>
</body>
</html>
6-1-3-2、函数参数的解构赋值
const array = [1, 1];
// const add = arr => arr[0] + arr[1];
// 我们可采用解构赋值的方式计算:
const add = ([x = 0, y = 0]) => x + y;
console.log(add(array));
console.log(add([]));
6-1-3-3、交换变量
let x = 1;
let y = 2;
// let tmp = x;
// x = y;
// y = tmp;
// console.log(x, y);
[x, y] = [y, x];
console.log(x, y);
6-2、对象的解构赋值
6-2-1、对象解构赋值原理
首先也是进行结构匹配,结构匹配上后,将属性名相同的完成赋值。
const { age, username } = { username: 'zhangsan', age: 18 };
// 完整写法:
const { age: age, username: username } = { username: 'zhangsan', age: 18 };
console.log(age, username); // 18 zhangsan
我们可以对解构的属性取别名:
const { age: age, username: name } = { username: 'zhangsan', age: 18 };
console.log(age, name);
6-2-2、对象解构赋值的默认值
对象解构赋值默认值的生效条件为:对象的属性值严格等于undefined时,对应的默认值才会生效。
const { username = 'zhangsan', age = 0 } = { username: 'lisi' };
console.log(username, age);// lisi 0
同样,与数组解构赋值默认值类似,对象解构赋值的默认值是表达式时也是惰性求值的。
6-2-3、对象解构赋值的注意事项
1、将一个已经声明的变量用于解构赋值的注意事项
let x = 1;
// let { x } = {x: 2}; //这里会报x已经声明的错误
// 那我们这样写呢:
// { x } = { x : 2}; // 注意这样也是不可以的,会被浏览器误认为是代码块的{}
// 所以我们此时要使用()包裹,让整个赋值在圆括号中进行:
({ x } = { x: 2});
- 所以,将已经声明的变量进行对象的解构赋值时,赋值过程要在圆括号中进行(以免让浏览器误认为对象的{}时函数体)
2、对象的解构赋值是可以取到继承的属性的
const { toString } = {};
console.log(toString); // f toString() {}
// 由于toString在Object的prototype属性上,所以可以顺着原型链找到
6-2-4、对象解构赋值的应用
6-2-4-1、对函数参数的解构赋值
// const logPersonInfo = user => console.log(user.username, user.age);
const logPersonInfo = ({ age = 0, username = 'zhangsan' }) => console.log(username, age);
logPersonInfo({ username: 'lisi', age: 18 }); // lisi 18
logPersonInfo({}); // zhangsan 0
6-2-4-2、对复杂嵌套对象进行解构赋值
const obj = {
x: 1,
y: [2, 3, 4],
z: {
a: 5,
b: 6
}
};
const {
y,
y: [, yy],
z,
z: { b }
} = obj;
console.log(yy, y, z, b); // 3 [2,3,4] {a:5, b: 6} 6
第一个y使用来取obj中的整个y属性对应的内容的,yy是用来取y对应数组的第二个索引对应的内容“3”的,z是用来取z属性对应的整个对象的,而b是用来取z属性对应对象中b属性对应的内容的。
6-3、字符串的解构赋值
字符串的解构赋值比较特殊,其既可以用数组的形式进行解构赋值,也可以用对象的形式进行解构赋值(而不能用字符串的形式进行解构赋值):
6-3-1、使用数组的形式进行解构赋值
const [a, b, , , c] = 'hello';
console.log(a, b, c); // h e o
6-3-2、使用对象的进行进行解构赋值
const { 0: a, 1: b, length } = 'hello';
console.log(a, b, length); // h e 5
console.log('hello'.length) // 5
按照对象的形式进行解构赋值时,属性值对应的是字符串的索引,想取第几个位置的字符,属性值就写几;除此之外还可以取出字符串的length属性(因为可以直接使用字符串上本身就有length属性)
6-4、数值与布尔值的解构赋值(扩展)
数值与布尔值进行解构赋值时不能使用数组的形式(因为它们没有length属性),只能使用对象的形式进行解构赋值,在使用对象形式对数值/布尔值进行解构赋值时,会尝试将数值/布尔值转换为对应的包装对象(Number Boolean)
const { a = 1, toString } = 123;
console.log(a, toString); // 1 f toString(){}
// 123上没有属性a,所以会输出默认值1,Number包装类上存在属性toString,所以会输出toString方法
同样:也可以使用对象的形式对布尔值进行解构赋值
const { b = 2, toString } = true;
console.log(b, toString); // 2 f toString(){}
6-5、undefined与null的解构赋值(扩展)
由于undefined与null没有对应的包装对象,无法通过它们转换成相应的对象,所以对它们进行解构赋值,都会报错
6-6、解构赋值常见场景汇总
6-6-1、交换变量
let a = 1;
let b = 2;
[a, b] = [b, a]; // 注意a与b已经声明过了,这里就不要添加let了
console.log(a, b); // 2 1
6-6-2、从函数返回多个值
函数只能返回一个值,如果要返回多个值,只能将这些值放入一个数组或对象里。此时我们可以使用解构赋值,可以很方便的提取出这些值:
function example() {
return [1, 2, 3];
}
let [a, b, c] = example();
console.log(a, b, c); // 1 2 3
function example2() {
return {
x: 1,
y: 2
};
}
let { x, y } = example2();
console.log(x, y); // 1 2
6-6-3、函数参数的定义
利用解构赋值也可以将一组参数与变量名对应起来:
function fun([x, y, z]) {
console.log(x, y, z); // 1 2 3
}
fun([1,2,3]);
function fun2({a, b, c}) {
console.log(a, b, c); // 2 3 1
}
fun2({c: 1, a: 2, b: 3});
6-6-4、指定函数参数的默认值
指定参数的默认值,就避免了在函数体内部再去判断传入的参数是否有值了
function foo({x, y = 5}) {
console.log(x, y);
}
foo({x: 1}); // 1 5
foo({x: 1, y: 2}); // 1 2
6-6-5、遍历Map解构
利用解构赋值去获取map的键名和键值就会很方便:
var map = new Map();
map.set('zs', '18');
map.set('ls', '20');
for(let [key, value] of map) {
console.log(`${key}今年${value}岁`);
}
6-6-6、加载模块
加载模块也利用了解构,可以让引入的部分更加明确
import {a, b} from 'xxx';
6-6-7、提取JSON数据
const jsonData = {
"name": "zs",
"age": "18",
"number": "17111111111"
}
let {name, age, number} = jsonData;
console.log(name, age, number);