这是我参与更文挑战的第8天,活动详情查看: 更文挑战
对象解构
ES6新增,同时执行多个赋值操作。MDN
将对象的某个属性提取到某个变量中。
基本用法
const herb = {
name: "herb",
age: 18
}
let herbName = herb.name,
herbAge = herb.age;
复制代码
以前的方法过于繁琐。
let { name: herbName, age: herbAge } = herb;
复制代码
现在通过这种方式,两段代码等效。
let { 属性名:变量名 } = 解构对象
let { name, age } = herb;
// 相当于:let name = herb.name; let age = herb.age;
复制代码
=
右边放要解构的对象,可以是返回一个对象的表达式。
=
左边的{}
括号里面,表示要把哪些属性名从对象那里解构出来,:
后面跟着变量名,就是说,属性名对应的属性值存放的地方。如果没有:
则表示属性名和变量名相同。
let name, age;
( { name, age } = herb );
复制代码
如果给事先声明的变量赋值,则赋值表达式必须包含在一对括号中。
解构赋值的同时定义默认值
const herb = {
name: "herb",
age: null
}
let { name: herbName = "person", age = 20, sex = "男" } = herb;
// name: "herb"
// age: undefined
// sex: "男"
复制代码
let { 属性名:变量名 = 默认值 } = 解构对象
herb.sex
不存在时,会使用默认值,或者对象中的属性值为undefiend
,也会用默认值。
上述代码,相当于:先定义了herbName
、age
、sex
三个变量,再从对象中:
前面的属性名读取出来赋值给这几个变量,如果属性值为undefined
,就使用默认值。
可以解构原型链上的属性
class Animal {
constructor(type, age, sex) {
this.type = type;
this.age = age;
this.sex = sex;
}
call() {
console.log("aaaa");
}
}
class Person extends Animal {
constructor(type, age, sex, name) {
super(type, age, sex);
this.name = name;
}
}
const herb = new Person("人类", 18, "男", "herb");
复制代码
let { name, age, sex, call } = herb;
// name: "herb"
// age: 18
// sex: "男"
// call: call() { console.log("aaaa") }
复制代码
可以把原型链上的属性也解构出来,无论是否可以遍历。
因为只要在原型链上就可以被对象访问到,所以也可以赋值给新的变量。
使用计算属性名
const arr = [1,2,3,4];
let { [Symbol.iterator]:it } = arr;
// it: function
let key = "z";
let { [key]: foo } = { z: "bar" };
// foo: "bar"
复制代码
可以结合使用。
隐式把待解构目标转换成对象
let { length } = "1234";
// length: 4
let { constructor:c } = 100;
// c == Number
复制代码
原始值会被转换成对象在进行解构。
let { a } = null
let { b } = undefined
复制代码
null
和undefined
不能被解构,否则会报错。
嵌套解构
const user = {
name: "herb",
age: 19,
sex: "男",
address: {
province: "浙江",
city: "嘉兴"
}
}
复制代码
let { address } = user;
// address
// {
// province: "浙江",
// city: "嘉兴"
// }
复制代码
解构出来是一个对象。
let { address: { province, city } } = user;
// address 不存在
// province: "浙江"
// city: "嘉兴"
复制代码
let
创建了province
和city
两个变量,不会创建address
,只是从user
里找到address
,并从address
里找到province
和city
。
let { province, city } = user.address;
复制代码
也可以这样写,直接在=
右边把要结构的对象找出来,不用在{}
里面嵌套解构了。
let { hobby: { food, sport } } = user;
// Uncaught TypeError: Cannot read property 'food' of undefined
复制代码
注意:外层属性没有定义的情况下不能使用嵌套结构。user
没有hobby
属性,对其进行嵌套解构肯定会出错。
数组解构
const arr = [0, 1, 2, 3, 4];
复制代码
const { 0: a, 4: e } = arr;
// a: 0
// e: 4
复制代码
数组本质上就是一个对象,所以可以通过对象的方式解构。
const [a, , , , e] = arr;
// a: 0
// e: 4
复制代码
数组也有自己的解构方式,用[]
表示,里面变量的顺序代表了arr
里面元素的顺序。省略了索引,是上一个写法的简化版本,但是要获取不连续的两个索引,要用,
分隔,表示跳过数组里多少元素。
const arr = [0, 1, [2, 3, 4]];
let [, , [c, d]] = arr;
// c: 2
// d: 3
let [two, three] = arr[2];
// two: 2
// three: 3
复制代码
也可以嵌套解构。
剩余参数
const user = {
name: "herb",
age: 19,
sex: "男",
address: {
province: "浙江",
city: "嘉兴"
}
}
复制代码
let { name, ...prop } = user;
// name: "herb"
// prop: {
// address: { province: "浙江", city: "嘉兴" }
// age: 19
// sex: "男"
// }
复制代码
...prop
剩余参数会把没有解构的属性全部收集起来,封装成新的对象。
可以很方便的把一个对象的某些属性剔除出来。
let {...prop1, age, ...prop2 } = user;
// Uncaught SyntaxError: Rest element must be last element
复制代码
注意:剩余参数只能出现在最后一位。
交换变量
let a = 1;
let b = 3;
[a, b] = [b, a];
复制代码
把a
和b
组装成一个数组,再通过解构交换变量。
a = a ^ b;
b = a ^ b;
a = a ^ b;
复制代码
也可以这样交换位置,但仅限于number类型。
复杂解构
const article = {
title: "文章标题",
content: "文章内容",
comments: [{
content: "评论1",
user: {
id: 1,
name: "用户名1"
}
}, {
content: "评论2",
user: {
id: 2,
name: "用户名2"
}
}]
}
// 解构出第二条评论的用户名和评论内容
复制代码
// 方法一
const {
comments: [, {
content,
user: {
name
}
}]
} = article;
// 方法二
const {
content,
user: {
name
}
} = article.comments[1]
复制代码
可以灵活运用。
For of 迭代和解构
for(let { user: { name }, content } of article.comments) {
console.log(name, content);
}
复制代码
利用上面的例子,通过for-of
可以轻松的把数组中每一个对象的具体属性都解构出来。
由于for-of
只能迭代那种实现了Iterable接口的数据类型,所以无法用于普通对象上。
const obj = {
a: 1,
b: 2
}
for(let prop of obj) {
console.log(prop);
}
// Uncaught TypeError: obj is not iterable
复制代码
参数解构
function print({ name, age, sex, address: { province, city } }) {
console.log(name, age, sex, province, city);
}
print({
name: "herb",
age: 19,
sex: "男",
address: {
province: "浙江",
city: "嘉兴"
}
});
复制代码
可以直接在形参上进行解构,省去了在函数体力反复调用对象获取值的过程。并且不会对arguments
产生影响,它依然保存着传进来的对象。
function ajax({
method = "get",
url = "/"
} = {}) {
console.log(method, url);
}
ajax({
method: "get",
url: "www.juejin.cn"
})
复制代码
在解构中使用默认值,考虑到了传进来的对象没有这个属性的情况。给形参设置默认值,防止不传对象进来,对undefined
进行解构的情况。代码变得简洁而健壮。