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

最近遇到了一個問題,來自於下面的一段代碼:javascript

let { [key]: id, ...rest } = obj
複製代碼

在這篇文章裏,我想解釋下它是在作什麼以及它是如何工做的。前端

提醒:由於它很是的晦澀難懂,因此我最終並無以這種方式實現去作,不過它是很是有趣的,值得去咱們去了解。java

如何遇到這個問題

假如咱們有如下數組git

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

咱們把它按照 group 字段進行分組映射以下:github

{
    '1': [
        { name: 'Michael' },
        { name: 'Lukas' },
    ],
    '2': [
        { name: 'Travis' },
    ]
}
複製代碼

如何從 users 對象中刪除 group 屬性,實現上述效果?數組

咱們能夠利用以下方法:bash

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

這裏用到了reduce 函數,若是不熟悉的同窗,能夠去查看相關資料就很少說了。函數

個人最終目標是使這個函數具備動態性,而如今是經過固定字段 group 來分組,並非計算得來的。假如之後想使用其餘字段進行分組就須要更改函數了。ui

在實現動態性以前咱們先看看spa

const { group, ...userData } = user
複製代碼

由於它也是這篇文章咱們想談論的知識。

解構

上面的數據中每一個用戶都有 groupname 屬性。所以在 ES6 中可使用解構的方式獲取對象中的值。

例如:

const { group } = user
複製代碼

它等效於

const group = user.group
複製代碼

還能夠這麼作

const { group, name } = user
複製代碼

它等效於

const group = user.group
const name = user.name
複製代碼

剩餘參數

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 以前,咱們來看一個簡單的例子。

分配新變量名

還記得這個嗎?

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 中。

最後,計算對象屬性名

其餘的都說完了,如今惟一解釋的就剩下 [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
複製代碼

原文:dev.to/mzanggl/let…
翻譯:六小登登
更多優質文章:六小登登的博客

我是:六小登登,一名愛寫做的技術人,從零開始自學前端,常活躍CSDN、掘金、公衆號等分享原創乾貨。 關注公衆號:六小登登,後臺回覆「1024」便可免費獲取驚喜福利!後臺回覆「加羣」羣裏天天都會全網蒐羅好文章給你。

相關文章
相關標籤/搜索