解构赋值
ES6 允许按照一定模式,从数组(对象)中提取值(属性),对变量进行赋值,这被称为解构。
本质上,这种写法属于“模式匹配”,只要等号两边的模式相同,左边的变量就会被赋予对应的值。
数组解构
数组的解构赋值为数组中提取值,按照对应位置,对变量赋值。
let [a,b,c] = [1,2,3]; //可以从数组中提取值,按照对应位置,对变量赋值。
//等价于
let a = 1;
let b = 2;
let c = 3;
let[first, ,] = ["1","2","3"] //first=1
let [ , , third] = ["foo", "bar", "baz"];//third=baz
let [x, , y] = [1, 2, 3]; //x =1 y=3
- 解构不成功,变量的值就等于undefined。
let [a,b,c] = [1,2];
console.log(a) //1
console.log(b) //2
console.log(c) //undefined
let [a] = []
console.log(a) //undefined
- 不完全解构,即等号左边的模式,只匹配一部分的等号右边的数组这种情况下,解构依然可以成功。
let [x,y] = [100,200,300]
console.log(x) //100
console.log(y) //200
- 解构赋值允许指定默认值
let [a = true] = []
console.log(a) //true
let [x,y = 'b'] = ['a']
console.log(x) //a
console.log(y) //b
对象解构
解构赋值只要两边结构相同就行,所以对象也是可以解构赋值的。
但是需要注意的是对象和数组的解构有一个很大的区别:对象的属性没有次序,变量必须与属性同名,就能取到正确的值。
let { foo , bar } = { foo: 'aaa', bar: 'bbb' };
console.log(foo)// "aaa"
console.log(bar)// "bbb"
//顺序反过来也适用,只要变量和属性同名,就能取到正确的值
let { bar, foo } = { foo: 'aaa', bar: 'bbb' };
foo // "aaa"
bar // "bbb"
解构赋值
- 将等号后的内容拥有的属性解构出来,赋值给等号前的内容
let {length:len} = "hello";
//length:等号后内容拥有的
//len:赋值给的对象
//将字符串"hello"的length赋值给len
console.log(len); //5
//创建一个对象,提取它的某一个值赋给另一个变量
var obj={name:"Lily",age:20,sex:"女"}
let {name:stu} = obj;
console.log(stu); //Lily
//必须提取到等号后内容所拥有的属性
let {email:stu1} = obj;
console.log(stu1); //undefined
字符串解构
字符串也可以解构赋值。此时,字符串被转换成一个类似数组的对象。
let [a,b,c,d,e] = "world";
let {length:len} = "world";
console.log(a) //"W"
console.log(b) //"o"
console.log(c) //"r"
console.log(len) //5
函数参数的解构赋值
函数的参数也可以解构赋值
function add([x, y]){ //add的参数是一个数组
return x + y;
}
add([1, 2]); // 3
//也可以使用默认值
//(1)
function fun({x = 0, y = 0} = {}) {
return [x, y];
}
fun({x: 3, y: 8}); // [3, 8]
fun({x: 3}); // [3, 0]
fun({}); // [0, 0]
fun(); // [0, 0]
上面代码中,函数fun的参数是一个对象,x和y的默认值都为0,通过对这个对象进行解构,得到变量x和y的值。
如果解构失败,x和y等于默认值。
//(2)
function gun({x, y} = { x: 0, y: 0 }) {
return [x, y];
}
gun({x: 3, y: 8}); // [3, 8]
gun({x: 3}); // [3, undefined]
gun({}); // [undefined, undefined]
gun(); // [0, 0]
上面代码中,函数gun的参数是一个对象,默认对这个对象进行解构,得到变量x和y的值都是0。
如果解构失败,x和y等于undefined。
(1)和(2)的区别在:(1)是给变量x和y指定默认值,(2)是给函数gun的参数指定默认值。
undefined和null
解构赋值的规则是,只要等号右边的值不是对象或数组,就先将其转为对象。 由于undefined和null无法转为对象,所以对它们进行解构赋值时都会报错
let { prop: x } = undefined; // 报错:TypeError
let { prop: y } = null; // 报错:TypeError
//那么,使用undefined和null去解构会怎么样呢?
let [a,b,c="小明"] = ["小李","小黄","小张"] //小李 小黄 小张
let [a,b,c="小明"] = ["小李","小黄",undefined] //小李 小黄 小明
//undefined不能赋值,则采用默认值
let [a,b,c="小明"] = ["小李","小黄",null] //小李 小黄 null
//null是一个有效值,因此不会触发默认值,会作为undefined赋值
圆括号的使用
如果变量在解构前就已经定义,此时再去解构就会出现问题。
let foo = 'abc' ;
{ foo } = { foo:'def' };
console.log(foo);
报错:
只需要在解构语句的外面加一个圆括号就可以运行
let foo = 'abc' ;
({ foo } = { foo:'def' })
console.log(foo); //def
解构赋值的常见应用场景
1.交换变量的值
let x=1,y=2;
[x,y] = [y,x];
console.log(x) //2
console.log(y) //1
//交换了x和y的值,操作简洁清晰
2.从函数返回多个值
一般函数只能返回一个值,如果要返回多个值,只能将它们放在数组或对象里返回。有了解构赋值,取出这些值就非常方便。
// 返回一个数组
function fun() {
return [1, 2, 3];
}
let [a, b, c] = fun(); //返回了数组[1,2,3]并赋值给[a,b,c]
// 返回一个对象
function gun() {
return {
foo: 1,
bar: 2
};
}
let { foo, bar } = gun();
3.函数参数的定义
//有序
function test([x,y,z]){
...
}
test([5,12,7]);
//无序
function test({ x, y, z }) { ... }
test({ y: 12, z: 7, x: 5 });
4.提取JSON数据
JSON
- 全称是 JavaScript Object Notation,即 JavaScript对象标记法。
- 是一种轻量级、基于文本的、可读的格式。
语法规则
- 数组(Array)用方括号(“[]”)表示。
- 对象(0bject)用大括号(“{}”)表示。
- 名称/值对(
name/value)组合成数组和对象。 - 名称(
name)置于双引号中,值(value)有字符串、数值、布尔值、null、对象和数组。 - 并列的数据之间用逗号(“
,”)分隔
let jsonData = {
"id": "43",
"name": "Andy",
"data": [867, 5309]
};
let { id, name, data: number } = jsonData;
console.log(id, name, number);
// 43, "Andy", [867, 5309]
5.遍历 Map 结构
任何部署了Iterator 接口* 的对象,都可以用for...of循环遍历。Map 结构* 原生支持 Iterator 接口,配合变量的解构赋值,获取键名和键值就非常方便。
(*Iterator 迭代器 对集合进行遍历,常用的方法:①hasnext():判断集合是否有下一个元素,有则返回true,没有返回false;②next():获取迭代的下一个元素, 存储String类型的元素)
(Map是一组键值对的结构,具有极快的查找速度,采用“键名(key)”-“键名(value)”的方式存储数据)
const map = new Map();
map.set('first', 'hello');
map.set('second', 'world');
for (let [key, value] of map) {
console.log(key + " is " + value);
}
// first is hello
// second is world
//也可以只获取键名和键值
// 获取键名
for (let [key] of map) {
// ...
}
// 获取键值
for (let [,value] of map) {
// ...
}
进阶属性
1.嵌套解构
解构赋值不仅可以解构一层结构,还可以嵌套地解构对象或数组中的内部属性
const user = {
id: 001,
name: 'Vita',
address: {
city: 'Shanghai',
zip: 200000
}
};
const {
name,
address: { city, zip }
} = user;
console.log(name); // "Vita"
console.log(city); // "Shanghai"
console.log(zip); // 200000
- 注:
address是中间变量,这里并不会声明变量address,而是直接提取其子属性。
2.函数返回值的结构与重命名
函数返回对象,重命名变量
function getUser() {
return { id: 1001, username: 'vita' };
}
const { id: userId, username } = getUser();
console.log(userId); // 1001
console.log(username); // "vita"
- 用冒号
:实现属性名与变量名不一致时的赋值。
3.结合数组方法使用解构(高阶函数)
- forEach 解构
const pairs = [[1, 'one'], [2, 'two'], [3, 'three']];
pairs.forEach(([key, value]) => {
console.log(`${key}: ${value}`);
});
// 输出:
// 1: one
// 2: two
// 3: three
- map 配合解构重组结构
const users = [
{ id: 1, name: 'A' },
{ id: 2, name: 'B' }
];
const names = users.map(({ name }) => name);
console.log(names); // ['A', 'B']
4.解构赋值 + rest 剩余运算符组合使用
可以通过rest剩余运算符获取后半部分的对象或数组
- 对象解构 + 剩余属性
const { a, b, ...rest } = { a: 1, b: 2, c: 3, d: 4 };
console.log(a); // 1
console.log(b); // 2
console.log(rest); // { c: 3, d: 4 }
- 数组解构 + 剩余元素
js
复制编辑
const [first, ...others] = [10, 20, 30, 40];
console.log(first); // 10
console.log(others); // [20, 30, 40]