什么是解构?ES6 允许按照一定模式,从数组和对象中提取值,对变量进行赋值,这被称为解构(Destructuring)。下面有8道解构使用的案例,来测试下自己的掌握程度,我会把案例和答案分来,方便先自己尝试回答输出结果。
案例
1 解构别名
let obj = {a: 1, b: 2}
let {a: b} = obj
console.log(b)
2 嵌套对象解构
let obj2 = {
a: 'hello',
b: [
'world',
{c: "!"}
]
}
let {b: [{c}]} = obj2
console.log(c)
3 数组解构
let [a, b, ...c] = [1]
console.log(a,b,c)
4 解构默认值
const fn = () => {
return 2
}
let [a = 1, b = fn(), c = 4] = [1, 3]
console.log(a, b, c)
5 解构的有效赋值
let [a, b = a, c = a, d = a] = [1, undefined, null, '']
console.log(a, b, c, d)
6 解构方法
let {toString: s} = 123
console.log(s === "123")
7 函数参数解构
console.log([[1, 2], [3, 4]].map(([a, b]) => a + b))
8 ?
let [a, b, c] = {a: 1, b: 2, c: 3}
console.log(a, b, c)
答案及解析
1 解构别名
let obj = {a: 1, b: 2}
let {a: b} = obj
console.log(b)
答案:1
说明:这句解构表示,要解构出来变量a,并且取别名叫b,不要被对象中的b变量干扰。
2 嵌套对象解构
let obj = {
a: 'hello',
b: [
'world',
{c: "!"}
]
}
let {b: [{c}]} = obj
console.log(c)
答案:undefined
说明:这段解构对象比较深层,我们需要解构的变量是c,所以我们排除掉其它干扰,剩下的解构就类似:let [{c}] = ['world',{c: "!"}]
,需要注意数组的解构是基于迭代器的,也就是说我们需要解构的变量和数组的值是一对一对应的,所以[{c}]
就表示从数组的第一项的对象中解构出来变量c,但是第一项是字符串,所以得到的结果就算undefined
3 数组解构
let [a, b, ...c] = [1]
console.log(a,b,c)
答案:1 undefined []
说明:解构顺序从左向右,如果解构不成功,变量的值等于undefined
,所以b是undefined
,c变量将剩余的值收集到数组中,由于数组中只有一个值并且赋值给了a变量,所有c为[]
。
实际开发从数组中解构的使用相对从对象中解构使用的少点,所以同理可以试下这个解构会输出什么?
let {a, b, ...c} = {a: 1, b: 2, c: 3, d: 4}
,输出a,b,c结果是1 2 { c: 3, d: 4 }
4 解构默认值
const fn = () => {
return 2
}
let [a = 1, b = fn(), c = 4] = [1, 3]
console.log(a, b, c)
答案:1 3 4
说明:解构是可以赋默认值兜底的,前提是解构失败的情况下,上面的代码a和b都能解构成功,所以默认值就不会生效,c解构失败所以使用默认值。
5 解构的有效赋值
let [a, b = a, c = a, d = a] = [1, undefined, null, '']
console.log(a, b, c, d)
答案: 1 1 null ''
说明:解构的过程,ES6内部使用 === 去判断一个位置是否等于undefined
,只有严格相等,默认值才会生效。所以上面的解构代码会拿数组的每项和undefined
做全等对比,只有b满足,所以b取默认值。
6 解构方法
let {toString: s} = 123
console.log(s === "123")
答案:false
说明:解构赋值时,如果等号右边是数值和布尔值,则会先转为对象,相当于(let {toString: s} = Number.prototype)。解构出来的toString只是方法并不会执行,所以s === Number.prototype.toString
才会返回true
7 函数参数解构
console.log([[1, 2], [3, 4]].map(([a, b]) => a + b))
答案:[ 3, 7 ]
说明:不看map的话,我们可以把函数看成是这样的([a,b]) => a+b
,表面上这个函数接收的是一个数组,但在传入参数的那一刻,数组参数就被解构成变量a
和b
。
8 ?
let [a, b, c] = {a: 1, b: 2, c: 3}
console.log(a, b, c)
答案:你会获得一个报错,TypeError:xxx is not iterable
说明:这个报错的意思是说后面这个对象是不可迭代的,原因是数组的解构是基于迭代器的(对象的解构是基于属性的枚举和复制),在js中普通的Object对象是不可迭代的,所以会报错。
如果想要这个解构不报错,我们需要为这个对象添加一个迭代器函数:
let obj = {a: 1, b: 2, c: 3}
obj[Symbol.iterator] = function () {
let index = 0
function next () {
return {done: index >= Object.keys(obj).length, value: obj[Object.keys(obj)[index++]]}
}
return {next}
}
let [a,b,c] = obj
console.log(a,b,c) // 1 2 3