let { [key]: id = 0, ...rest } = obj-极限解构

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

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

假如我们有以下数组

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

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

{
    '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
}, {})

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

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

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

const { group, ...userData } = user

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

1.解构

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

const { group } = user

它等效于

const group = user.group

还可以这么做

const { group, name } = user

它等效于

const group = user.group
const name = user.name
2.剩余参数
const { group, ...userData } = user

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

userData = {
    name: "xx"
}

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

const location = { country: 'Japan', city: 'Tokyo' }

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

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

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

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

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

class BaseArray extends Array {
    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;
    }, {})
}

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

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

3.分配新变量名
const user = { group: 1 }
const { group } = user
console.log(group) //1

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

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

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

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

例如:

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

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

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

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

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

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

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

const { group: id } = user
我们获取属性 group 的值,并将其放入变量 id 中。

4.计算对象属性名

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

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

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

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

const key = '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} = user

使用计算属性,它变成

let { [key]: id = 0, ...rest } = obj
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值