最近遇到了一个问题,来自于下面的一段代码:

let { [key]: id, ...rest } = obj

在这篇文章里,我想解释下它是在做什么以及它是如何工作的。

提醒:因为它非常的晦涩难懂,所以我最终并没有以这种方式实现去做,不过它是非常有趣的,值得去我们去了解。

如何遇到这个问题的

假如我们有以下数组

const users = [     { name: 'Michael', group: 1 },    { name: 'Lukas', group: 1 },    { name: 'Travis', group: 2 },]    { name: 'Michael', group: 1 },    { name: 'Lukas', group: 1 },    { name: 'Travis', group: 2 },]

我们把它按照 group 字段进行分组映射如下:

{    '1': [        { name: 'Michael' },        { name: 'Lukas' },    ],    '2': [        { name: 'Travis' },    ]}'1': [        { name: 'Michael' },        { name: 'Lukas' },    ],    '2': [        { name: 'Travis' },    ]}

如何从 users 对象中删除 group 属性,实现上述效果?

我们可以利用如下方法:

users.reduce((result, user) => {  const { group, ...userData } = user  result[group] = result[group] || []  result[group].push(userData)  return result}, {})  const { group, ...userData } = user  result[group] = result[group] || []  result[group].push(userData)

  return result}, {})

这里用到了reduce 函数,如果不熟悉的同学,可以去查看相关资料就不多说了。

我的最终目标是使这个函数具有动态性,而现在是通过固定字段 group 来分组,并不是计算得来的。假如以后想使用其他字段进行分组就需要更改函数了。

在实现动态性之前我们先看看

const { group, ...userData } = user

因为它也是这篇文章我们想谈论的知识。

解构

上面的数据中每个用户都有 groupname 属性。因此在 ES6 中可以使用解构的方式获取对象中的值。

例如:

const { group } = user

它等效于

const group = user.group

还可以这么做

const { group, name } = user

它等效于

const group = user.groupconst name = user.nameconst name = user.name

剩余参数

const { group, ...userData } = user

现在,这段代码有一个更复杂的问题需要我们讨论。

...userData 获取了除 group 之外的所有值,并把它们浅拷贝到一个新的常量 userData 中。在这种情况下 userData 变成一个仅有 name 属性的对象。

userData = {    name: "xx"}"xx"}

在这里,我们不要混淆剩余参数和扩展运算,它们其实刚好是相反的。

const location = { country: 'Japan', city: 'Tokyo' }const newLocation = { ...location, zipcode: 123456 }//{country: "Japan", city: "Tokyo", zipcode: 123456}country: 'Japan', city: 'Tokyo' }

const newLocation = { ...location, zipcode: 123456 }//{country: "Japan", city: "Tokyo", zipcode: 123456}

这里将会把 location 对象的属性全部展开,然后放入 newLocation 对象中。此时的  newLocation 对象将包含如下属性:

{country: "Japan", city: "Tokyo", zipcode: 123456}"Japan", city: "Tokyo", zipcode: 123456}

那么什么时候是「剩余参数」,什么时候是扩展运算?这将取决于赋值在哪边,在赋值左边的就是剩余参数,在赋值右边的就是扩展运算。

你也可以在函数中使用剩余参数

class BaseArray extends Array {    constructor(...values) { // rest        super(...values) // spread    }}    constructor(...values) { // rest        super(...values) // spread    }}

此时让我们来看看实现函数动态性的解决方案:

function groupBy(array, key) {    return array.reduce((result, item) => {        const { [key]: id, ...rest } = item        result[id] = result[id] || []        result[id].push(rest);        return result;    }, {})}    return array.reduce((result, item) => {        const { [key]: id, ...rest } = item        result[id] = result[id] || []

        result[id].push(rest);

        return result;    }, {})}

现在到底什么是 const { [key]: id, ...rest } = item ?

我们已经知道 ...rest 意味着什么了。所以我们就不说了。在解释 [key]: id 之前,我们来看一个简单的例子。

分配新变量名

还记得这个吗?

const user = { group: 1 }const { group } = userconsole.log(group) //1group: 1 }const { group } = userconsole.log(group) //1

如果我们将 group 的值去转换为一个变量名为发生什么?我们可以这么做

const user = { group: 1 }const { group: id } = userconsole.log(id) //1group: 1 }const { group: id } = userconsole.log(id) //1

此时将会把 group 的值赋值给变量 id。

这实际上是非常有用的,因为有些时候对象的 key 作为变量名是无效的。

例如:

const foo = { 'fizz-buzz': true }const { 'fizz-buzz' } = foo 'fizz-buzz': true }const { 'fizz-buzz' } = foo 

此时程序就会报错, 因为 fizz-buzz 不可以当作变量名使用。正确的写法如下:

const { 'fizz-buzz': fizzBuzz } = foo'fizz-buzz': fizzBuzz } = foo

那么我们该如何记住这个语法呢?其实是很简单的,这和我们创建对象时使用的是完全相同的语法。

const id = 1const user = {    group: id}1const user = {    group: id}

因此,如果对象是在赋值(=)的右边,group 属性保存变量 id。

如果它是在赋值(=)的左边,它刚好是相反的。

const { group: id } = usergroup: id } = user

我们获取属性 group 的值,并将其放入变量 id 中。

最后,计算对象属性名

其他的都说完了,现在唯一解释的就剩下 [key].了。

我们可以使用它来访问计算属性名,在我们的例子中变量 key 的值是 group。

创建对象时如何添加计算 keys ?

使用相同的语法,只是它在赋值(=)的右边。

const key = 'group'const id = 1const user = {    [key]: id}'group'const id = 1

const user = {    [key]: id}

但是如果我们只写 let { [key] } = obj 那么我们应该用什么名字来访问这个变量呢?我们是不能这样的。

因此,就像 fizz-buzz 一样,我们最终的方式就是:[key]: id

所以就是这样,我们还可以设置默认值应用于 id。

通常会是这样的

const user = { group: 1 }const { group = 0, createdAt = null} = usergroup: 1 }

const { group = 0, createdAt = null} = user

使用计算属性,它变成

let { [key]: id = 0, ...rest } = obj

原文:https://dev.to/mzanggl/let--key-id--0-rest---obj---destructuring-to-the-limit-deo        
翻译:六小登登

我是:六小登登,一名爱写作的技术人,从零开始自学前端,常活跃CSDN、掘金、公众号等分享原创干货。
关注公众号:六小登登,后台回复「1024」即可免费获取惊喜福利!后台回复「加群」群里每天都会全网搜罗好文章给你。


上文:《90单身原因TOP3》

推荐:《Javascript中你必须理解的执行上下文和调用栈》

let { [key]: id = 0, ...rest } = obj-让解构发挥到极限相关推荐

  1. UE4之Obj模型解构解析

    由于需求,必须研究obj模型的结构. 参考: Wavefront OBJ 英文文档 Warefront Object File (.obj)文档 obj + mtl 格式 三维模型obj文件的格式解析 ...

  2. 20181210-es6(letconst解构模版字符串原理 展开运算符、剩余运算符运用 深拷贝原理 reduce原理 箭头函数)...

    变量声明 var 特点: 1.可以重复声明 2.不能定义常量 3.不支持块级作用域 复制代码 let //1.不存在预解释 变量提升 //2.暂时性死区 //3.具备块级,同一块内不能重复声明;let ...

  3. 前端学习必备之ES6解构赋值的常见用法

    1.解构赋值可以轻松获取对象或者数组中的数据 var jsonData = {data: "111",data2: ["test","test2&qu ...

  4. ECMAScript 6入门 - 变量的解构赋值

    定义 ES6允许按照一定模式,从数组和对象中提取值,对变量进行赋值,这被称为解构(Destructuring). 解构赋值不仅适用于var命令,也适用于let和const命令. 解构赋值的规则是,只要 ...

  5. es6学习 -- 解构赋值

    ES6 允许按照一定模式,从数组和对象中提取值,对变量进行赋值,这被称为解构(Destructuring). 以前,为变量赋值,只能直接指定值. let a = 1; let b = 2; let c ...

  6. JavaScript学习笔记 -- ES6学习(三) 变量的解构赋值

    1.解构赋值的定义 在ES6中,允许按照一定模式,从数组和对象中提取值(所谓解构),然后对变量进行赋值. var a = 1; var b = 2; var c = 3;//等价于var [a, b, ...

  7. exec 直接赋值_了解 JavaScript 解构赋值

    引言 数组和对象就像一个 "压缩包". 在需要单独引用数组中的某一个元素时,解构赋值可以很方便的完成这个任务,它可以将数组和对象整体 "解压缩" 到一堆变量上, ...

  8. ES6解构赋值: ES6...转为ES5的写法

    es6的特性,主要用于 数组和对象的析构 直接上问题: 因为chrome低版本(用的55版本)不支持es6...的下面这种写法, 需要转为es5写法 function calcLinePaths() ...

  9. 解构赋值(Destructuring)

    解构赋值(Destructuring) ES6 允许按照一定模式,从数组和对象中提取值,对变量进行赋值,这被称为解构(Destructuring). 数组的解构赋值 以前,为变量赋值,只能直接指定值. ...

最新文章

  1. [转]Asp.Net 上传大文件专题(3)--从请求流中获取数据并保存为文件[下]
  2. 基于ArduinoLeonardo板子的BadUSB攻击实战
  3. python画出的雷达图效果-PYTHON绘制雷达图代码实例
  4. 由浅入深:自己动手开发模板引擎——置换型模板引擎(四)
  5. DDoS攻击的大量增加给企业带来了新的威胁——Vecloud
  6. IntelliJ IDEA 添加项目后编译显示包不存在的解决方案
  7. 腕上“小型手机”!小米手表万事俱备 坐等发布
  8. 在提交消息中链接到GitHub上的问题编号
  9. 微信接口开发之高级篇系列【网页授权获取用户基本信息】
  10. 一篇文章带你搞懂 SpringBoot与Swagger整合
  11. mysql可视化工具
  12. Rasa对话机器人连载一 第121课:Rasa对话机器人Debugging项目实战之电商零售对话机器人运行流程调试全程演示-1
  13. 微信小程序开发之路(3)— 添加一个Button按钮点击事件
  14. oracle数据库快速查询关键字,数据库分页查询关键字
  15. flink watermark 生成机制与总结
  16. 网络安全-使用PGP实现电子邮件安全
  17. 【R_绘图】绘图字体设为Times New Roman
  18. 京东超级秒杀时间html,京东418超级秒杀节LOGO及使用规范
  19. nested exception is org.apache.ibatis.binding.BindingException: Parameter ‘email‘ not found. Availab
  20. 转:Jenkins+Jmeter+ant接口自动化框架for Linux学习

热门文章

  1. C++ 输入年月,打印出这个月的日历
  2. 计算机模拟comsol,基于COMSOL固体氧化物燃料电池(SOFC)的数值模拟仿真
  3. matlab调幅举例,基于MATLAB的单边带调幅和解调的实现设计.doc
  4. 慕尼黑计算机学院大旋梯,欧洲四国自由行(7)--德国佛莱堡/新天鹅堡/慕尼黑/柏林...
  5. 视频实例分割paper(一)《Video Instance Segmentation》
  6. 操作电脑:谨防“腕管综合症”
  7. 【微信小程序】--WXML WXSS JS 逻辑交互介绍(四)
  8. Java 实现长图文生成
  9. 关于计算机技术的英文,关于计算机技术在教育中的多方应用 中英文对照.doc
  10. 机械结构工程师的日常