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,
(完)
轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/117365.html
標籤:JavaScript
下一篇:前端之html
