为何这些解构赋值行为不等价?如何合并嵌套解构赋值?
我来帮你拆解这个嵌套解构的问题~你原本分开写的两次解构是完全正确的,但尝试合并成一行时出错了,核心原因是对解构赋值的表达式返回值理解有误,咱们一步步来看:
问题回顾
你原本的正确写法是先从this中解构出market(不存在则用空对象),再从market中解构context1和context2:
const { [pair.market]: market = {}, } = this; const { [pair.context]: context1 = {}, [pair.target]: context2 = {}, } = market;
你尝试合并成一行的写法是:
const { [pair.context]: context1 = {}, [pair.target]: context2 = {}, } = { [pair.market]: market = {}, } = this;
但当market[pair.context]或market[pair.target]已存在时,行为不符合预期,这是为什么呢?
原因分析
JavaScript中,赋值表达式的返回值是被赋值的右边的值,而不是解构后的结果。你写的{ [pair.market]: market = {}, } = this这个表达式,它的返回值是this本身,而不是解构出来的market对象。
所以合并后的代码实际上等价于:
// 先执行赋值表达式,把this赋值给左边的对象模式,同时解构出market { [pair.market]: market = {}, } = this; // 然后从this中直接解构context1和context2,而不是从market中 const { [pair.context]: context1 = {}, [pair.target]: context2 = {}, } = this;
这就完全偏离了你的意图——你本来想从market里解构context1和context2,但实际是从this(也就是markets对象)里直接取这些属性,而markets一开始并没有A、B这类属性,所以即使market里已经有对应属性,这行代码也会忽略它们,直接使用默认的空对象,导致行为不符合预期。
正确的合并写法
要实现和两次解构完全一致的效果,你需要使用嵌套解构,直接在解构this的同时,深入解构[pair.market]内部的属性:
const { [pair.market]: { [pair.context]: context1 = {}, [pair.target]: context2 = {}, } = {} // 给market设置默认空对象,避免pair.market不存在时解构报错 } = this;
这个写法的逻辑和你分开写的两次解构完全一致:
- 从
this中取出pair.market对应的属性,赋值给内部的解构模式,如果不存在则用空对象 - 从这个属性(或默认空对象)中,分别取出
pair.context和pair.target对应的属性,赋值给context1和context2,不存在则用空对象
验证修改后的代码
把你的addPair函数改成用嵌套解构,测试效果和原来完全一致:
const pair1 = { context: 'A', target: 'B', market: 'MARKET1', price: '0.1', }; const pair2 = { context: 'A', target: 'C', market: 'MARKET1', price: '1', }; const pair3 = { context: 'C', target: 'B', market: 'MARKET2', price: '0.1', }; function addPair(pair) { // 使用嵌套解构合并两次操作 const { [pair.market]: { [pair.context]: context1 = {}, [pair.target]: context2 = {}, } = {} } = this; this[pair.market] = { ...market, [pair.context]: { ...context1, [pair.target]: { price: +(pair.price), }, }, [pair.target]: { ...context2, [pair.context]: { price: +(1 / pair.price), }, }, }; } const markets = {}; addPair.call(markets, pair1); addPair.call(markets, pair2); addPair.call(markets, pair3); console.log(markets);
运行这段代码,输出结果和你原来的代码完全相同,说明嵌套解构的写法是正确的。
总结
解构赋值的嵌套写法需要遵循“逐层深入”的原则,不要混淆赋值表达式的返回值和解构的目标对象。记住:当你想从某个解构出来的对象里再解构属性时,直接在解构模式里嵌套对象结构即可,这样就能保证逻辑和多次解构一致啦~
内容的提问来源于stack exchange,提问作者neaumusic

