JavaScript與函數式編程

来源:https://www.cnblogs.com/xhyccc/archive/2020/04/19/12732445.html
-Advertisement-
Play Games

JavaScript與函數式編程 絕大多數編程語言都會有函數的概念(或者說所有的?我不太確定),他們都可以做出類似的操作: 但是Javascript更適合函數式編程,因為函數對於js來說,是 一等公民 。 我們可以把匿名函數賦值給一個變數,比如: 然後我們可以將這個函數賦值給另一個變數: 這樣做和直 ...


JavaScript與函數式編程

絕大多數編程語言都會有函數的概念(或者說所有的?我不太確定),他們都可以做出類似的操作:

function(x) {
  return x * x
}

但是Javascript更適合函數式編程,因為函數對於js來說,是一等公民

我們可以把匿名函數賦值給一個變數,比如:

let pow = function(x) {
  return x * x
}

然後我們可以將這個函數賦值給另一個變數:

let comeon = pow
comeon(x)

這樣做和直接調用pow(x)是一樣的效果。

甚至於我們可以將函數作為參數傳入另一個函數,這樣,諸多小函數可以匯聚在一起,變得異常強大!

filter()

OK,我們接下來看一些比較基礎的例子。

首先是filter(),這是我最喜歡的函數之一。filter()方法會創建一個新的數組,並且我們可以傳入一個判斷函數,將符合條件的元素,放入新的數組。

現在我們有一個數組,裡面存放了很多游戲,每個元素都記錄了該游戲需要花多少錢:

let games = [
  {
    name: '英雄聯盟',
    cost: 45
  },
  {
    name: '穿越火線',
    cost: 888
  },
  {
    name: '魔獸世界',
    cost: 75
  },
  {
    name: '征途',
    cost: 1000000
  }
]

然後我們需要找出,花費不超過一百元的游戲,該怎麼做呢?

可能是這樣:

let target = []
for(let i = 0; i < games.length; i++) {
  if(games[i].cost <= 100) {
    target.push(games[i])
  }
}

這是大家從大學開始學C語言的時候就會用的方法。但是我現在想用filter()方法重寫它:

let target = games.filter((game) => {
  return game.cost <= 100
})

Wow! Awesome!

我稍微解釋一下,防止有同學沒有看懂,這裡傳入了一個函數,函數接收了一個參數,這個參數就是games的每一個元素依次傳入的值,在每一次傳入之後,我們都返回一個邏輯值,這個邏輯值取決於該游戲的cost是否小於100,如果返回了true該元素就會被放到新的數組裡去,反之同理。

註意:

  • filter()不會對空數組進行檢測
  • filter()不會改變原始數組

實際上,filter內部的處理方法可能和我們使用for迴圈一模一樣!但是我們利用函數式編程,寫了更少的代碼、更少的邏輯。Less code! Less time! Less bug!

這就是函數式編程的美妙之處。

map()

我們現在先看回之前寫的數組:

let games = [
  {
    name: '英雄聯盟',
    cost: 45
  },
  {
    name: '穿越火線',
    cost: 888
  },
  {
    name: '魔獸世界',
    cost: 75
  },
  {
    name: '征途',
    cost: 1000000
  }
]

現在我們要把每一款游戲的名字都拿出來,組成一個新的數組。

這種操作是非常常見的,比如我們使用React,向伺服器請求了JSON數據,接下來需要在這裡渲染名字,那裡渲染價格……等等。

let gameName = games.map((item) => {
  return item.name
})

我們甚至可以做出更多的騷操作,比如說:

let gameName = games.map((item) => {
  return `${item.name}是一個${item.cost > 100? '坑錢游戲':'良心游戲'}`
})

得到結果["英雄聯盟是一個良心游戲", "穿越火線是一個坑錢游戲", "魔獸世界是一個良心游戲", "征途是一個坑錢游戲"]

Wow! Awesome! 只能用優雅兩個字來形容!

reduce()

reduce()單詞本身是減少的意思,但是實際上你可以將reduce()理解為求和(事實並不如此,reduce更加強大且靈活,但是此時可以暫時這麼理解,更多特性可以在下一節看到)。

語言太過蒼白無力,我們來看看代碼:

let numbers = [1, 2, 3, 4, 5]
let sum = numbers.reduce((total, item) => total + item)

這裡是利用了箭頭函數可以省略return的特性。

這裡的傳入的函數接收了兩個參數(實際上可以接收四個,但這裡不需要後面兩個),這兩個參數通過英文應該就可以看懂。

reduce()方法接收一個函數作為累加器,數組中的每個值(從左到右)開始縮減,最終計算為一個值。

註意: reduce()對於空數組是不會執行回調函數的。

這裡可以給一個初始值:

let numbers = [1, 2, 3, 4, 5]
let sum = numbers.reduce((total, item) => {
  return total + item
}, 10)

之前的和是15,這次加上了一個初始值,就是25了。

實踐

假設我們有一個TXT文件。

徐航宇	游泳	4分鐘
徐航宇	跑步	1分鐘
徐航宇	跳遠	3米
劉好	游泳	5分鐘
劉好	跑步	2分鐘
劉好	跳遠	1米

我們用node去讀取他,讓它變成一個JSON對象,就像這樣:

{
  "徐航宇": [
    {
      "項目": "游泳",
      "時間": "4分鐘"
    },
    {
      "項目":"跑步",
      "時間":"1分鐘"
    }
  ],
  "劉好": [
    // ...
  ]
}

上代碼!

import fs from 'fs'

let output = fs.readFileSync('data.txt', 'utf-8')
	.trim() // 去掉字元串頭尾的空格,返回新數組
	.split('\n') // 在換行處截斷,組成數組
	.map(line => line.split('\t')) // 每一行根據製表符斷開,組成數組

這一步之後,我們應該得到什麼?

[
  ["徐航宇", "游泳", "4分鐘"],
	["徐航宇", "跑步", "1分鐘"],
	["徐航宇", "跳遠", "3米"],
	["劉好", "游泳", "5分鐘"],
	["劉好", "跑步", "2分鐘"],
	["劉好", "跳遠", "1米"]
]

接下來想要變成對象,該怎麼做呢?

首先第一步,我們想一想,要想變成最終的JSON數據,我們需要對每一項進行處理:

  • 把每一個數組的第一個作為對象的屬性名
  • 把每一個數組的二三項組成新的對象,放入該屬姓名的值中

接下來就該reduce()出場了:

.reduce((customer, line) => {
  	// 提取每個數組的第一項,作為傳入對象的屬姓名
  	// 如果該項是以前沒有的,那麼將其初始化為空數組
  	// 如果該項以前有,那麼就不動他
    customer[line[0]] = customer[line[0]] === undefined ? [] : customer[line[0]]
		customer[line[0]].push({
      name: line[1],
      time: line[2]
    })
    return customer
  }, {})

這樣就成功了!

總結

總而言之,函數式編程如果歸根結底,和直接寫沒有任何區別。但是它提供給了我們一種寫更少的代碼,完成更多的事情的方法。

人是難免會出錯的,代碼量越大、錯誤可能就會越多,所以更少代碼的函數式編程,往往意味著:更少的bug。

(完)


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 先說兩句 上一講 "「Vuex 到底是個什麼鬼」" ,已經完美詮釋了 Vuex 的牛逼技能之所在(純屬自嗨)。如果把 Vuex 比喻成農藥裡面的劉備,那就相當於你現在已經知道了劉備他是一個會打槍的力量型英雄,而且他打的槍還是雙排量的,認識到這一點後,那麼接下來就是要瞭解他到底是如何打槍的,是左手打, ...
  • 在日常開發中,我們可能會遇到將一個數組中裡面的重覆值去除,那麼,我就將我自己所學習到的幾種方法分享出來 去除數組重覆值方法: 1,利用indexOf()方法去除 思路:創建一個新數組,然後迴圈要去重的數組,然後用新數組去找要去重數組的值,如果找不到則使用.push添加到新數組,最後把新數組返回回去就 ...
  • 選項卡是前端常見的基本功能,它是用多個標簽頁來區分不同內容,通過選擇標簽快速切換內容。學習本教程之前,讀者需要具備html和css技能,同時需要有簡單的javascript基礎。 先來完成html部分。首先,需要一個元素把整個選項卡包含在內。新建一個div元素,它的id命名為tabBox,如下所示: ...
  • 作用域和閉包-執行上下文: 變數提升(寫代碼時千萬不要先使用再定義) <script> console.log(a);//undefined var a=10; fn('cyy',18); function fn(name,age){ age=20; console.log(name,age);// ...
  • 在前端面試時,面試官經常會問:瀏覽器是多進程還是單進程? 瀏覽器是多進程的,瀏覽器每一個 tab 標簽都代表一個獨立的進程(也不一定,因為多個空白 tab 標簽會合併成一個進程),瀏覽器內核(瀏覽器渲染進程)屬於瀏覽器多進程中的一種。 瀏覽器每個進程有多個線程,主要有以下線程 1)GUI 渲染線程: ...
  • VSCode卸載後進行重新安裝,發現新安裝的還有原來的一些配置,卸載的不徹底,有時候也容易出問題,可按照如下方法卸載乾凈: 1.進入控制面板卸載VSCode,也可以在VSCode的安裝目錄下用程式自帶的卸載程式(這個沒有親自試過.....) 2.這樣卸載完後還有一些配置文件,要想完全卸載,還需要將一 ...
  • 一、承接連載4 3.null和undefined沒有toString()方法,調用就會報錯 var num1 = undefined; console.log(num1.toString()); ​ var num2 = null; console.log(num2.toString()); 二、S ...
  • 定時器功能分析 核心思路: 定義一個變數,根據定時器,每秒執行一次,每次執行++自增操作 變數存儲的數值,就會每秒+1 現在需要的記錄效果,是每0.01秒,也就是10毫秒執行一次 根據累計的數值,執行進位 ms 如果達到 100,就是1秒 如果 秒 達到 60 就是 1分鐘 如果 分鐘 達到 60  ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...