ES6解构赋值详解:数组与对象的高级用法

作者:异步漫步

时间:2026-10-30

浏览:269

本文深入解析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有所帮助。

实用工具推荐

电子包浆

绿化、压缩、噪点和虚拟水印,自由调节做旧程度。

使用 ›
图片压缩

选择画质和输出格式,预览压缩前后的大小。

使用 ›
相关文章