ES6解构赋值详解:数组与对象的高级用法
本文深入解析ES6中的解构赋值语法,涵盖数组与对象的基础提取、嵌套结构处理及Rest操作符用法。重点讲解对象属性重命名、默认值设置及已声明变量赋值的括号包裹技巧,并指出直接返回解构值的常见误区,帮助开发者写出更简洁高效的JavaScript代码。
解构赋值基础概念
什么是解构?
解构操作与数据构造过程相反。它不用于创建新的对象或数组,而是将现有的对象或数组拆解,逐个提取出其中所需的数据。
ES6引入了一种新的模式匹配机制,解构赋值便基于此模式运行。该机制会映射出待解构数据的结构,仅提取与模式相匹配的数据部分。
被解构的数据源位于赋值运算符 = 的右侧,可以是任意组合的数组或对象,且支持任意层级的嵌套。左侧用于接收数据的变量数量不受限制。
数组解构详解
数组解构
数组解构利用一个数组作为数据源,通过定义“数组模式”来匹配并提取所需数值,进而赋值给一个或多个变量。
数组模式依据数值在数组中的位置进行匹配。该模式必须精确映射数组结构,确保模式中的每个变量都能获得右侧数组中对应位置的值。
通过几个示例来辅助理解:
数组模式示例
将数组中的所有数值分别赋值给独立的变量。
// 设置数组
const avengers = ['Tony Stark', 'Steve Rogers', 'Natasha Romanoff'];
// 把数组解构赋值给变量。数组模式位于赋值运算符 `=` 的左侧,被结构的数组在
// 其右侧。
const [ironMan, cap, blackWidow] = avengers;
// ironMan = 'Tony Stark'
// cap = 'Steve Rogers'
// blackWidow = 'Natasha Romanoff'
// 输出 ironMan:
ironMan;
提取除第一个元素外的所有数值。
const avengers = ['Tony Stark', 'Steve Rogers', 'Natasha Romanoff'];
// 我们不用用到Tony
const [, cap, blackWidow] = avengers;
// ironMan = Error: undefined
// cap = 'Steve Rogers'
// blackWidow = 'Natasha Romanoff'
// 输出 cap:
cap;
提取除第二个元素外的所有数值。
const avengers = ['Tony Stark', 'Steve Rogers', 'Natasha Romanoff'];
// cap 缺失
const [ironMan, , blackWidow] = avengers;
// ironMan = 'Tony Stark'
// cap = Error: undefined
// blackWidow = 'Natasha Romanoff'
// 输出 blackWidow:
blackWidow;
提取除最后一个元素外的所有数值。
const avengers = ['Tony Stark', 'Steve Rogers', 'Natasha Romanoff'];
// ironMan vs cap
const [ironMan, cap] = avengers;
// ironMan = 'Tony Stark'
// cap = 'Steve Rogers'
// blackWidow = Error: undefined
// 输出 blackWidow:
ironMan;
嵌套数组
这种匹配模式同样支持嵌套数组,只要确保赋值运算符 = 左侧的数组模式与右侧数组结构一致即可。无论嵌套层级多深,左侧的变量都会获得右侧数组中对应位置的值。
解构嵌套的数组
// Destructuring Nested Arrays
const avengers = [
'Natasha Romanoff',
['Tony Stark', 'James Rhodes'],
['Steve Rogers', 'Sam Wilson']
];
// Avengers and their partners
const [blackWidow, [ironMan, warMachine], [cap, falcon]] = avengers;
// blackWidow = 'Natasha Romanoff'
// ironMan = 'Tony Stark'
// warMachine = 'James Rhodes'
// cap = 'Steve Rogers'
// falcon = 'Sam Wilson'
// Output warMachine:
warMachine;
从深层嵌套的数组中提取特定值。
// 从该数组中提取 Pepper Potts
const avengers = [
'Natasha Romanoff',
[['Tony Stark', 'Pepper Potts'], 'James Rhodes'],
['Steve Rogers', 'Sam Wilson']
];
// Destructure
const [ , // 跳过 'Natasha Romanoff'
[[ , // 跳过 'Tony Stark'
hera // Pepper Potts 赋值给变量 'hera'
]]] = avengers;
// 请注意:你也可以这样写
// const [, [[, hera ]]] = avengers;
// 输出 hera:
hera;
// hera = 'Pepper Potts'
运用rest操作符捕获所有剩余项
若需获取特定数组项并将其余项收集到数组中,可使用 rest操作符 进行解构:
// 通过rest操作符解构
const avengers = ['Natasha Romanoff', 'Tony Stark', 'Steve Rogers'];
const [blackWidow, ...theOthers] = avengers;
theOthers;
// blackWidow = 'Natasha Romanoff'
// theOthers = ['Tony Stark', 'Steve Rogers']
// 输出 theOthers:
theOthers;
对象解构与嵌套处理
对象解构
对象解构在处理复杂、深层嵌套对象时尤为强大。其规则与数组解构一致:在赋值运算符左侧构建“对象模式”,使变量位置与右侧对象的值位置相匹配。
在对象解构中,需明确指定要提取的属性名称及目标变量名。如同数组解构,需在赋值运算符左侧创建对象模式以映射源对象。
在此场景下,我们提取的是对象属性的值(例如从 prop: value 中提取 value)。因此,对象模式中必须包含一个变量,其位置需与待提取属性值的位置一致。
简单示例
提取一个简单的对象属性值。
我们可以将对象 { ironMan: 'Tony Stark' } 的属性 ironMan 的值 'Tony Stark' 赋值给变量 a:
//解构对象的属性值,赋给单个变量 `a`:
const { ironMan: a } = { ironMan: 'Tony Stark' };
// 输出 a:
a; // a = 'Tony Stark '
提取多个属性值。
通过扩展相同模式,可从单个对象中提取多个属性值,如下所示:
// Setup our object
const avengers = {
ironMan: 'Tony Stark',
cap: 'Steve Rogers',
blackWidow: 'Natasha Romanoff'
};
// Destructure object to individual variables
const {
ironMan: a,
cap: b,
blackWidow: c
} = avengers;
// a = 'Tony Stark '
// b = 'Steve Rogers'
// c ='Natasha Romanoff'
// Output a:
a;
观察此解构模式如何精确匹配被解构对象。
嵌套的对象解构
与解构嵌套数组类似,无论层级多深,均可对嵌套对象进行解构。
// Setup our object
const avengers = {
blackWidow: 'Natasha Romanoff',
ironManCharacters: {
couple: {
ironMan: 'Tony Stark',
hera: 'Pepper Potts',
},
partner: {
warMachine: 'James Brodie'
}
},
capCharacters: {
cap: 'Steve Rogers',
partner: {
falcon: 'Sam Wilson'
}
}
};
// Destructure object to individual variables
const {
blackWidow: a,
ironManCharacters: {
couple: {
ironMan: b,
hera: c
},
partner: {
warMachine: d
}
},
capCharacters: {
cap: e,
partner: {
falcon: f
}
}
} = avengers;
// a = 'Natasha Romanoff'
// b = 'Tony Stark '
// c = 'Pepper Potts'
// d = 'James Brodie'
// e = 'Steve Rogers'
// f = 'Sam Wilson'
// Output a:
a;
给赋值的变量命名
将变量命名为 a、b、c 等无意义名称并非最佳实践,变量名应具有明确的语义。
冗长式命名
// Setup our object
const avengers = {
ironMan: 'Tony Stark',
cap: 'Steve Rogers',
blackWidow: 'Natasha Romanoff'
};
// Destructure object to individual variables with meaningful names
const {
ironMan: ironMan,
cap: cap,
blackWidow: blackWidow
} = avengers;
// blackWidow = 'Natasha Romanoff'
// ironMan = 'Tony Stark '
// cap = 'Steve Rogers'
// Output blackWidow:
blackWidow;
虽然比使用 a、b、c 命名更好,但仍可优化。 { ironMan: ironMan } 形式显得冗长且不直观。
语法上命名捷径
若要将对象属性值赋给同名变量,可在赋值运算符 = 左侧的模式中直接书写属性名,无需额外指定变量名,如下所示:
// Setup our object
const avenger = {
ironMan: 'Tony Stark'
};
// Destructure object to individual variables with meaningful names
const {
ironMan // equivalent to 'ironMan: ironMan'
} = avenger;
// ironMan = 'Tony Stark '
// Output ironMan:
ironMan;
由于被解构的对象属性名称与赋值变量名称相同,只需列出名称一次即可。
语法简洁
对前述代码稍作调整,可使代码更加简洁明了:
// Setup our object
const avengers = {
ironMan: 'Tony Stark',
cap: 'Steve Rogers',
blackWidow: 'Natasha Romanoff'
};
// Destructure object to individual variables with meaningful names
const { ironMan, cap, blackWidow } = avengers;
// Output ironMan:
ironMan;
从对象中提取一个深层嵌套的属性。
当提取深层嵌套的对象属性时,情况变得更为有趣:
// Setup our object
const avengers = {
blackWidow: 'Natasha Romanoff',
ironManCharacters: {
couple: {
ironMan: 'Tony Stark',
hera: 'Pepper Potts',
},
partner: {
warMachine: 'James Brodie'
}
},
capCharacters: {
cap: 'Steve Rogers',
partner: {
falcon: 'Sam Wilson'
}
}
};
// Destructure a deeply nested object
const { ironManCharacters: { couple } } = avengers;
// couple = {
// ironMan: 'Tony Stark',
// hera: 'Pepper Potts',
// }
// Output couple:
couple;
这段代码应如何解读?变量 couple 又是如何定义的?
通过拆解可见,赋值运算符 = 左侧即为被解构对象的映射:
const avengers = {
ironManCharacters: {
couple: {
ironMan: 'Tony Stark',
hera: 'Pepper Potts',
}
}
};
const {
ironManCharacters: {
couple
}
} = avengers;
// Output couple:
couple;
仅使用 const { couple } = avengers; 无法提取 couple 的值。必须映射出要提取的对象属性的位置与名称,JS 编译器才能沿对象属性链查找并准确提取所需值。
此处需注意 couple 使用了语法捷径进行变量命名,实际逻辑如下:
const {
ironManCharacters: {
couple: couple
}
} = avengers;
couple 由此被定义,其值为对象 avengers 中名为 couple 的属性值。
给对象的属性解构赋值
此前我们主要将解构值赋给独立变量,实际上也可将解构值赋给另一个对象的属性。
const avengers = {
blackWidow: 'Natasha Romanoff',
ironManCharacters: {
couple: {
ironMan: 'Tony Stark',
hera: 'Pepper Potts'
}
}
};
const ironManProperties = {
family: {}
};
({
ironManCharacters: {
couple: ironManProperties.family
}
} = avengers);
ironManProperties.family
// ironManProperties.family = {
// ironMan: 'Tony Stark',
// hera: 'Pepper Potts'
// }
// Output ironManProperties.family:
ironManProperties.family;
此处我们将 ironManCharacters.couple 的值赋给了 ironManProperties.family 属性,需说明两点:
1.解构赋值必须被包含在 圆括号 内
当对已存在的变量(如示例中的 ironManProperties)进行解构时,必须如此操作,而非声明新变量。
2.模式仍然相匹配
{ ironManCharacters: { couple... } } 与对象 avengers 中的 ironManCharacters 相匹配。这允许从 avengers 对象中提取 ironManCharacters.couple 的值。然而,couple 后放置了新对象 ironManProperties 及其属性 family,实际被赋值的是该对象的属性 ironManProperties.family。
若对此感到困惑,可在 jsfiddle 中运行上述代码以直观理解。
若不清楚此用法场景,请参考后续文章示例。这些示例展示了如何利用此模式解构 API 调用的 JSON 对象,展现解构的强大之处。
默认值与常见陷阱
默认值
解构时,还可为变量指定默认值:
// Setup our object
const avengers = {
ironMan: 'Tony Stark',
cap: 'Steve Rogers',
blackWidow: 'Natasha Romanoff'
};
// Destructure using defaults
const { ironMan, cap, blackWidow, theHulk='Bruce Banner' } = avengers;
// ironMan = 'Tony Stark'
// cap = 'Steve Rogers'
// blackWidow = 'Natasha Romanoff'
// theHulk = 'Bruce Banner'
// Output blackWidow:
blackWidow;
解构时要避免出现这些问题
解构赋值时没有使用 const, let, var
前文在对象属性解构赋值时已提及,此处再次强调以加深印象。
不能对已经声明的变量进行解构
即只能在声明变量的同时进行解构赋值。
// Setup our object
const avengers = {
ironMan: 'Tony Stark',
cap: 'Steve Rogers',
blackWidow: 'Natasha Romanoff',
theHulk: 'Bruce Banner'
};
// Valid destructuring
const { ironMan } = avengers;
let { cap } = avengers;
var { blackWidow } = avengers;
// Invalid destructuring
let theHulk;
{ theHulk } = avengers;
// Error
// Output theHulk:
theHulk;
之所以不能对已声明变量直接解构,是因为若使用花括号 {,JavaScript 会将其解析为代码块声明。
解决方法是将整个解构赋值表达式包裹在一对 圆括号 内。
如何对一个已声明的变量进行解构赋值
// Setup our object
const avengers = {
ironMan: 'Tony Stark',
cap: 'Steve Rogers',
blackWidow: 'Natasha Romanoff',
theHulk: 'Bruce Banner'
};
// A valid Hulk
let theHulk;
({ theHulk } = avengers);
// theHulk = 'Bruce Banner'
// Output theHulk:
theHulk;
此时不再以花括号开头,JS 不会将其识别为代码块声明,从而达成预期的解构结果。
直接返回一个被解构的值
若未先声明返回变量而直接返回解构值,无法达到预期。例如,下方代码将返回整个 ironMan 对象,而非预期的 Tony Stark。
// Note: this doesn't work!
function getTonyStark(avengers){
return { ironMan: { realName } } = avengers;
// return the avengers object, not the realName value
}
const avengers = {
ironMan: {
realName: 'Tony Stark'
}
};
const tonyStark = getTonyStark(avengers);
// tonyStark = {
// ironMan: {
// realName: 'Tony Stark'
// }
// };
// Output tonyStark:
tonyStark;
要从被解构对象中提取值,需先将其赋值给变量,再返回该变量,如下代码所示:
// Note: this DOES work!
function getTonyStark(avengers){
const { ironMan: { realName } } = avengers;
return realName;
}
const avengers = {
ironMan: {
realName: 'Tony Stark'
}
};
const tonyStark = getTonyStark(avengers);
// tonyStark = 'Tony Stark'
// Output tonyStark:
tonyStark;
将赋值与返回分两行书写虽显繁琐且代码冗长,但这是 JavaScript 的工作机制——必须先将解构值赋给变量,再单独返回,两步不可合并。
然而,虽需分开操作,却不必分两行书写。如下单行写法同样能达到预期效果:
function getTonyStark(avengers){
return ({ ironMan: { realName } } = avengers) && realName;
}
const avengers = {
ironMan: {
realName: 'Tony Stark'
}
};
const tonyStark = getTonyStark(avengers);
// tonyStark = 'Tony Stark'
// Output tonyStark:
tonyStark;
由于 JavaScript 的 _short-circuit_ 逻辑操作符 (&& 和 ||) 会基于第一个操作数的值返回第二个操作数的值,此写法生效。第一个操作数为解构赋值表达式,将值赋给 realName;realName 作为第二个操作数,其值最终被返回。
此法并非最佳实践,但可行。在追求代码简短的同时,务必注意代码的可读性。
总结 本文深入讲解了 解构赋值 的主要原则。解构不仅能减少你的代码量,还能从根本上改变你的编码方式。用的越多,你就会发现越多塑造数据和函数的方式,这些实现方式在过去几乎是不可能的。希望本文对大家学习ES6有所帮助。
D3.js 比例尺与坐标轴的配置详解
2026-11-05 16:54:46
JavaScript怎么遍历对象的Symbol键和不可枚举属性
2026-11-05 13:13:39
封装一个健壮的JS字符串判空工具函数
2026-11-05 12:16:14
JavaScript合并数组的三种常用方法:concat、扩展运算符与push
2026-11-05 11:22:29
JavaScript立即执行函数(IIFE)是什么及基本语法
2026-11-05 10:51:19
