JavaScript >> Javascript 文檔 >  >> Tags >> map

JavaScript 中如何使用 Map 動態修改數組

如何在 JavaScript 中使用 .map() 方法動態修改對像數組。

開始使用

因為我們為本教程編寫的代碼是“獨立的”(意味著它不是更大的應用程序或項目的一部分),所以我們將從頭開始創建一個 Node.js 項目。如果您的計算機上尚未安裝 Node.js,請先閱讀本教程,然後再返回此處。

在計算機上安裝 Node.js 後,從計算機上的項目文件夾(例如,~/projects ),為我們的工作創建一個新文件夾:

終端

mkdir map

接下來,cd 進入該目錄並創建一個 index.js 文件(這是我們編寫教程代碼的地方):

終端

cd map && touch index.js

接下來,在同一個文件夾中,運行 npm init -f 引導一個 package.json 文件:

終端

npm init -f

這將告訴 NPM(節點包管理器)創建一個新的 package.json 文件在您的應用程序中。 -f 部分代表“強制”,將跳過您在運行 npm init 時看到的分步嚮導 本身(隨意使用它來了解它是如何工作的)。

最後,我們需要安裝兩個依賴:dayjscurrency.js .

終端

npm i dayjs currency.js

作為 .map() 的一部分,我們將使用這兩個對我們的數據進行一些分析和格式化 .

有了這個,我們就可以開始了。

添加用戶數據

我們本教程的目標是使用 Array.map() JavaScript 中的方法來格式化一些用戶數據並幫助我們了解我們最有價值的用戶是誰。首先,讓我們在項目根目錄的單獨文件中添加一些測試數據:

/users.js

export default [
  {
    "createdAt": "2021-12-08T16:20:14+00:00",
    "invoices": [
      {
        "createdAt": "2021-12-08T16:20:14+00:00",
        "amount": 790.31
      },
      {
        "createdAt": "2021-12-07T16:20:14+00:00",
        "amount": 893.38
      },
      {
        "createdAt": "2021-12-06T16:20:14+00:00",
        "amount": 302.97
      },
      ...
    ],
    "name": {
      "first": "Wester",
      "last": "Christian"
    },
    "emailAddress": "[email protected]"
  },
  ...
];

注意:這是一個簡短的列表,因為真正的列表(在 Github 上可用)相當長。

一旦你在應用程序中有了它,我們就可以繼續編寫我們的 .map() 在這個數組上的函數。

映射用戶數組

首先,讓我們為 .map() 構建一個骨架 功能並審查並討論它是如何工作的:

/index.js

import users from './users.js';

const spendByUser = users.map((user) => {
  // We'll return our modified user here...
});

console.log(spendByUser);

回到我們的 /index.js 文件,在這裡,我們導入我們的 /users.js 文件為 users (記住,我們有一個 export default 在那個文件中,所以我們可以說 import users 在我們的代碼中——如果這是一個命名導出,我們會看到類似 import { users } from '...' )。

因為我們知道 users 變量應該包含一個數組(我們從 /users.js ),我們可以調用 .map() 直接上它。這是因為 .map() 是 JavaScript 中的一個內置函數。它在 Array 上定義 原型(用於包含由 JavaScript 中的函數繼承的功能的對象的名稱)。我們說大寫“A”Array 因為這是 JavaScript 中定義數組行為的函數。作為其原型對象的一部分,我們有 .map() 函數(稱為方法,因為它是在現有對像上定義的函數)。

像它的兄弟姐妹一樣,.map() 允許我們對數組執行循環並執行某事 . 某物 在這種情況下是修改數組中的元素並返回它們,使用修改後的元素創建一個新數組。一個簡單的例子:

const greetings = ['Hello', 'Goodbye', 'See ya'];

const greetingsWithName = greetings.map((greeting) => {
  return `${greeting}, Ryan!`
});

console.log(greetingsWithName);

// ['Hello, Ryan!', 'Goodbye, Ryan!', 'See ya, Ryan!']

這裡我們取一個字符串數組並使用 .map() 循環遍歷該數組。對於數組中的每個字符串,我們返回一個新字符串(使用反引號創建,因此我們可以利用 JavaScript 的字符串插值)。作為對 greetings.map() 的調用的回報 我們得到一個新數組。 理解很重要 :這是一個全新的、獨特的陣列。 .map() 函數創建一個副本 我們稱之為 .map() 的任何數組 函數並返回該新數組。

在這裡,我們將其存儲在變量 greetingsWithName 中 然後是 console.log() 出來看看修改後的副本。

/index.js

import dayjs from 'dayjs';
import users from './users.js';

const spendByUser = users.map((user) => {
  return {
    isLegacyCustomer: dayjs(user?.createdAt).isAfter(dayjs().subtract(60, 'days')),
    name: `${user?.name?.first} ${user?.name?.last}`,
  };
});

console.log(spendByUser);

現在我們了解了 .map() 的基本原理 ,讓我們開始修改我們的users 大批。與我們在上面看到的完全相同的原理在起作用:我們採用一個數組,調用 .map() 在它上面,並得到一個新的數組作為回報。

在頂部,請注意​​在我們的 users 上方 import 我們已經導入了我們之前安裝的依賴項之一:dayjs .在我們的 .map() 中 函數,在回調中我們傳遞給 .map() ,我們正在返回一個對象。我們的目標是對每個用戶進行一些“分析”,並確定每個客戶的消費金額以及他們是否是老客戶。

注意:我們不必從 .map() 返回完全相同的對象形狀(或者甚至是一個對象) .我們只需要返回我們想要替換數組中我們正在映射的當前項的任何內容。

在這裡,我們要創建一個具有三個屬性的新對象:

  1. isLegacyCustomer 它告訴我們一個布爾值 truefalse 客戶是否被視為舊客戶。
  2. name 這是用戶/客戶的全名字符串。
  3. spend 這是他們與我們一起花費的金額,由他們的 invoices 總數組成 數組。

在這裡,我們只關注 isLegacyCustomername (spend 有點複雜,所以我們接下來會添加)。

對於 isLegacyCustomer ,我們想知道用戶是否是在 60 多天前在我們的數據庫中創建的(我們只是在這裡假裝)。為了找出答案,我們採用 createdAt user 上的屬性 對象並將其傳遞給 dayjs() (上面是我們從同名包中導入的函數)。

dayjs 是一個用於操作和處理日期的庫。在這裡,為了讓我們的工作更輕鬆,我們使用 dayjs() 告訴我們是否傳遞了時間戳(user.createdAt ) 是之後 我們正在通過另一個調用 dayjs 即時創建另一個日期 :dayjs().subtract(60, 'days') .在這裡,我們得到一個 dayjs 包含現在之前 60 天的日期的對象。

作為回應,我們期望 .isAfter() dayjs 中的函數 返回一個布爾值 truefalse .

對於 name 字段,我們使用我們之前看到的相同反引號模式創建一個字符串,這次使用插值連接(連接在一起)我們用戶的名字和姓氏(使用 name.firstname.last name 的屬性 對象)。

/index.js

import dayjs from 'dayjs';
import currency from 'currency.js';
import users from './users.js';

const spendByUser = users.map((user) => {
  return {
    isLegacyCustomer: dayjs(user?.createdAt).isAfter(dayjs().subtract(60, 'days')),
    name: `${user?.name?.first} ${user?.name?.last}`,
    spend: user?.invoices?.reduce((total, invoice) => {
      total += invoice.amount;
      return currency(total, { precision: 2 }).value;
    }, 0),
  };
});

console.log(spendByUser);

現在是棘手的部分。為了得到 spend 屬性,我們需要使用另一個數組方法 .reduce() 循環 user.invoices 大批。類似於 .map() , .reduce() 方法循環或迭代調用該方法的數組。

然而,不是返回一個新數組,而是一個 .reduce() 方法返回我們分配給 acc 的任何值 或“蓄能器”。 reduce 函數中的累加器是一個以某個值開頭的值,如果我們使用的是 .reduce() 出於預期目的——返回該值的修改或“更新”版本。

在這裡,累加器以 0 開頭 作為第二個參數傳遞給 user?.invoices?.reduce() (那裡的問號只是說“如果用戶存在,並且發票存在,請致電 .reduce()user.invoices ")。對於 user.invoices 的每個循環或迭代 ,累加器的當前值(同樣,從 0 ) 作為第一個參數傳遞給我們傳遞給 .reduce() 的函數 ,這裡標記為 total .作為第二個參數,我們可以訪問正在循環的數組中的當前項。

如果我們在這裡查看我們的代碼,我們的目標是“匯總”invoice.amount user.invoices 中每個對象的字段 數組。

對於我們的 .reduce() 的每次迭代 ,我們取total的當前值 並添加當前的 invoice.amount 給它。接下來,我們將生成的 total 並將其傳遞給 currency() 我們從 currency.js 導入的函數 在我們文件的頂部。這有助於我們將貨幣值正確格式化為浮點數(例如,123.45 )。給那個函數,我們傳遞 total 作為第一個參數,然後是帶有 precision: 2 的函數的選項對象 作為屬性,表示“將此數字格式化為兩位小數。”

最後,我們返回 .value 調用 currency(total, { precision: 2 }) 返回的對象的屬性 .我們的return 這裡成為累加器的新值或“更新”值,可用作 totaluser?.invoices 的下一個循環/迭代中 .所以很清楚,total 在我們的代碼中,使用此示例數組的每次迭代都會得到以下內容(假設我們從 0 開始 ):

[{ amount: 1 }, { amount: 2.55 }, { amount: 3.50 }]

total = 0 // first item
total = 1
total = 3.55
total = 7.05 // last item

一旦我們的 .reduce() 完成後,我們期望取回 total 的最終值 (在添加最後一項之後)作為回報。這意味著 spend 應包含總 spend 為我們的每一位用戶。

而已!如果我們試一試(確保退出 spendByUser 在我們文件的底部),我們應該得到這樣的東西:

[
  { isLegacyCustomer: true, name: 'Wester Christian', spend: 10729.91 },
  { isLegacyCustomer: true, name: 'Carthon Weaver', spend: 14926.53 },
  { isLegacyCustomer: true, name: 'Keldrin Durham', spend: 13491.61 },
  { isLegacyCustomer: true, name: 'Jurgen Espinosa', spend: 13179.59 },
  ...
]

最後,讓我們看看如何利用這些數據。

根據映射數據排序

那麼我們為什麼要做這樣的事情呢?像大多數事情一樣,這取決於我們的代碼和我們正在處理的項目。但是,為了添加上下文,我們可以假設我們正在嘗試根據客戶在我們公司的總支出來尋找獎勵。現在我們已經有了映射數組,我們可以這樣做:

/index.js

import dayjs from 'dayjs';
import currency from 'currency.js';
import users from './users.js';

const spendByUser = users.map((user) => { ... });

const mostValuableCustomer = spendByUser.sort((a, b) => a.spend - b.spend).pop();
console.log({ mostValuableCustomer });

在這裡,我們添加了兩行。我們創建了一個變量 mostValueCustomer 為此,我們正在設置調用 .sort() 的結果 方法(另一個 Array 原型方法)並傳遞給它一個函數。該函數獲取數組中的當前項和下一項,並比較它們以找出哪個應該先出現。在這裡,我們按總支出排序,表示“從頂部花費最少的開始,到底部花費最多的結束。”

有了這個結果(我們希望得到我們 spendByUser 的排序副本 數組),我們稱之為 .pop() 方法說“彈出數組中的最後一項並返回它。”在這裡,最後一項(具有最高 spend 的客戶 ) 存儲在 mostValuableCustomer 多變的。如果我們將這個變量記錄下來,這就是我們在運行代碼時應該得到的結果:

{ mostValuableCustomer: { isLegacyCustomer: false, name: 'Vicente Henry', spend: 15755.03 } }

總結

在本教程中,我們學習瞭如何使用 Array.map 方法來遍歷現有數組並修改其內容。我們還學習瞭如何將數據格式化為 .map() 的一部分 以及如何在我們的代碼中使用生成的數據。


Tutorial JavaScript 教程
  1. 在 Microsoft App Center 上簽署 React Native Android APK

  2. JavaScript 中的實用函數式編程 - 為什麼值得

  3. 用 Deno 編寫你的第一個 API

  4. 使用 React 和 Auth0 極其簡單的客戶端身份驗證

  5. 如何在 PWA 或網站中使用帶有 SASS 變量的 Bootstrap

  6. 在Angular9中的“window.alert”之後無法退出該功能

  7. 在 JavaScript 中測試非導出函數

  1. 你現在需要知道的 50 個 Javascript Snippets

  2. 如何將 React 類組件轉換為函數組件

  3. VueJS 函數 API RCS 階段

  4. 為您的隨機背景顏色生成對比文本

  5. 如何在 Nuxt.JS 中使用樣式資源模塊?

  6. 如何使用渲染創建公關評論應用程序

  7. Bearcam Companion:放大和反應

  1. 為什麼同步 .env 文件不適用於機密管理

  2. Project 33 of 100 - 帶有 Firebase 和 React Hooks 的簡單運行跟踪器

  3. Let's Showwcase - 一個連接、構建、展示和成長的平台

  4. JavaScript 更改 URL 參數 |示例代碼