介紹

在 Javascript 中,函數就是值(一等公民)。這意味著它們可以分配給變數和/或作為值傳遞。

let random = function(){
    return Math.random()
}

let giveMeRandom = random // assigning random to a variable

這項知識使我們能夠用這種語言編寫函數式程式設計。在函數式程式設計中,我們大量使用高階函數。

高階函數?

高階函數是將其他函數作為參數返回函數作為結果的函數。

以其他函數作為參數通常稱為“回調函數”,因為它是由高階函數回調的。這是 Javascript 常用的概念。

例如,陣列上的 map 函數是一個高階函數。 map 函數接受一個函數作為參數。


const double = n => n * 2

[1, 2, 3, 4].map(double) // [ 2, 4, 6, 8 ]

或者,使用匿名函數:

[1, 2, 3, 4].map(function(n){
    return n * 2
}) // [ 2, 4, 6, 8 ]

map 函數是該語言內建的眾多高階函數之一。 sortreducefilterforEach 是該語言內建的高階函數的其他範例。

高階函數可讓您編寫更簡單、更優雅的程式碼。讓我們看看如果沒有這樣的抽象,上面的程式碼會是什麼樣子。讓我們用循環取代 map 函數:

let array = [1, 2, 3, 4]
let newArray = []

for(let i = 0; n < array.length; i++) {
    newArray[i] = array[i] * 2
}

newArray // [ 2, 4, 6, 8 ]

組合的力量

盡可能使用高階函數的一大優點是組合。

我們可以建立更小的函數,只處理一個邏輯。然後,我們透過使用不同的較小函數來組合更複雜的函數。

這種技術減少了錯誤並使我們的程式碼更易於閱讀和理解。

透過學習使用高階函數,您可以開始編寫更好的程式碼。

例子

讓我們試著舉個例子。假設我們有一個教室的成績清單。我們的教室有 5 個女孩,5 個男孩,每個人的成績都在 0 到 20 之間。

var grades = [
    {name: 'John', grade: 8, sex: 'M'},
    {name: 'Sarah', grade: 12, sex: 'F'},
    {name: 'Bob', grade: 16, sex: 'M'},
    {name: 'Johnny', grade: 2, sex: 'M'},
    {name: 'Ethan', grade: 4, sex: 'M'},
    {name: 'Paula', grade: 18, sex: 'F'},
    {name: 'Donald', grade: 5, sex: 'M'},
    {name: 'Jennifer', grade: 13, sex: 'F'},
    {name: 'Courtney', grade: 15, sex: 'F'},
    {name: 'Jane', grade: 9, sex: 'F'}
]

我想了解一些關於此事的事情:

  • 該班的平均成績

  • 男生的平均成績

  • 女孩的平均成績

  • 男孩中音調較高的

  • 女孩中的最高調

我們將嘗試使用高階函數來獲得簡單易讀的程式。讓我們從編寫可以協同工作的簡單函數開始:

let isBoy = student => student.sex === 'M'

let isGirl = student => student.sex === 'F'

let getBoys = grades => (
    grades.filter(isBoy)
)

let getGirls = grades => (
    grades.filter(isGirl)
)

let average = grades => (
    grades.reduce((acc, curr) => (
        acc + curr.grade
    ), 0) / grades.length
)

let maxGrade = grades => (
    Math.max(...grades.map(student => student.grade))
)

let minGrade = grades => (
    Math.min(...grades.map(student => student.grade))
)

我寫了7個函數,每個函數都有一份工作,而且只有一份工作。

isBoyisGirl 負責檢查一名學生是男孩還是女孩。

getBoysgetGirls 負責將所有男孩或女孩帶出教室。

maxGrademinGrade 負責取得某些資料中的最高和最低等級。

最後,average負責計算一些資料的平均等級。

請注意,average 函數還不知道它要處理的資料類型。這就是構圖之美。我們可以在不同的地方重複使用我們的程式碼。我可以將此功能與其他功能一起使用。

現在,我們已經有了編寫高階函數所需的東西:


let classroomAverage = average(grades) // 10.2
let boysAverage = average(getBoys(grades)) // 7
let girlsAverage = average(getGirls(grades)) // 13.4
let highestGrade = maxGrade(grades) // 18
let lowestGrade = minGrade(grades) // 2
let highestBoysGrade = maxGrade(getBoys(grades)) // 16
let lowestBoysGrade = minGrade(getBoys(grades)) // 2
let highestGirlsGrade = maxGrade(getGirls(grades)) // 18
let lowestGirlsGrade = minGrade(getGirls(grades)) // 9

請注意,外部函數(例如average)始終將內部函數的輸出作為輸入。因此,組合的唯一條件是確保輸出和輸入匹配。

而且因為每個函數只負責一件事,所以它使我們的程式碼更容易除錯和測試。


原文出處:https://dev.to/damcosset/higher-order-functions-in-javascript-4j8b


共有 0 則留言