javascript函數式_JavaScript中的函數式編程原理

javascript函數式

After a long time learning and working with object-oriented programming, I took a step back to think about system complexity.

經過長時間的學習和使用面向對象的編程,我退后了一步來思考系統的復雜性。

“Complexity is anything that makes software hard to understand or to modify." — John Outerhout

“Complexity is anything that makes software hard to understand or to modify. “ —約翰·奧特豪特

Doing some research, I found functional programming concepts like immutability and pure functions. Those concepts enable you to build side-effect-free functions, so it is easier to maintain systems — with some other benefits.

通過研究,我發現了函數式編程概念,例如不變性和純函數。 這些概念使您能夠構建無副作用的功能,因此更易于維護系統-還有其他好處 。

In this post, I will tell you more about functional programming, and some important concepts, with a lot of code examples in JavaScript.

在本文中,我將通過JavaScript的許多代碼示例向您詳細介紹函數式編程和一些重要概念。

什么是函數式編程? (What is functional programming?)

Functional programming is a programming paradigm — a style of building the structure and elements of computer programs — that treats computation as the evaluation of mathematical functions and avoids changing-state and mutable data — Wikipedia

函數式編程是一種編程范例-一種構建計算機程序的結構和元素的風格-將計算視為對數學函數的評估,并且避免了狀態和可變數據的更改- 維基百科

純功能 (Pure functions)

The first fundamental concept we learn when we want to understand functional programming is pure functions. But what does that really mean? What makes a function pure?

當我們想了解函數式編程時,我們學習的第一個基本概念是純函數 。 但這到底是什么意思? 是什么使函數純凈?

So how do we know if a function is pure or not? Here is a very strict definition of purity:

那么我們如何知道一個函數是否pure呢? 這是一個非常嚴格的純度定義:

  • It returns the same result if given the same arguments (it is also referred as deterministic)

    如果給定相同的參數,它將返回相同的結果(也稱為deterministic )

  • It does not cause any observable side effects

    它不會引起任何明顯的副作用

如果給定相同的參數,它將返回相同的結果 (It returns the same result if given the same arguments)

Imagine we want to implement a function that calculates the area of a circle. An impure function would receive radius as the parameter, and then calculate radius * radius * PI:

假設我們要實現一個計算圓的面積的函數。 一個不純函數將接收radius作為參數,然后計算radius * radius * PI

let PI = 3.14;const calculateArea = (radius) => radius * radius * PI;calculateArea(10); // returns 314.0

Why is this an impure function? Simply because it uses a global object that was not passed as a parameter to the function.

為什么這是不純功能? 僅僅是因為它使用了未作為參數傳遞給函數的全局對象。

Now imagine some mathematicians argue that the PI value is actually 42and change the value of the global object.

現在想象一些數學家認為PI值實際上是42并且會更改全局對象的值。

Our impure function will now result in 10 * 10 * 42 = 4200. For the same parameter (radius = 10), we have a different result.

我們的不純函數現在將導致10 * 10 * 42 = 4200 。 對于相同的參數( radius = 10 ),我們得到不同的結果。

Let's fix it!

讓我們修復它!

let PI = 3.14;const calculateArea = (radius, pi) => radius * radius * pi;calculateArea(10, PI); // returns 314.0

Now we’ll always pass the value of PI as a parameter to the function. So now we are just accessing parameters passed to the function. No external object.

現在,我們將始終將PI的值作為參數傳遞給函數。 因此,現在我們只訪問傳遞給函數的參數。 沒有external object

  • For the parameters radius = 10 andPI = 3.14, we will always have the same the result: 314.0

    對于參數radius = 10PI = 3.14 ,我們將始終具有相同的結果: 314.0

  • For the parameters radius = 10 andPI = 42, we will always have the same the result: 4200

    對于參數radius = 10PI = 42 ,我們將始終具有相同的結果: 4200

讀取文件 (Reading Files)

If our function reads external files, it’s not a pure function — the file’s contents can change.

如果我們的函數讀取外部文件,則它不是純粹的函數-文件的內容可以更改。

const charactersCounter = (text) => `Character count: ${text.length}`;function analyzeFile(filename) {let fileContent = open(filename);return charactersCounter(fileContent);
}

隨機數生成 (Random number generation)

Any function that relies on a random number generator cannot be pure.

任何依賴隨機數生成器的函數都不能是純函數。

function yearEndEvaluation() {if (Math.random() > 0.5) {return "You get a raise!";} else {return "Better luck next year!";}
}

它不會引起任何明顯的副作用 (It does not cause any observable side effects)

Examples of observable side effects include modifying a global object or a parameter passed by reference.

可觀察到的副作用的示例包括修改全局對象或通過引用傳遞的參數。

Now we want to implement a function to receive an integer value and return the value increased by 1.

現在我們要實現一個函數,以接收一個整數值并返回增加了1的值。

let counter = 1;function increaseCounter(value) {counter = value + 1;
}increaseCounter(counter);
console.log(counter); // 2

We have the counter value. Our impure function receives that value and re-assigns the counter with the value increased by 1.

我們有對counter 。 我們的不純函數會收到該值,然后將值增加1的值重新分配給計數器。

let counter = 1;const increaseCounter = (value) => value + 1;increaseCounter(counter); // 2
console.log(counter); // 1

Observation: mutability is discouraged in functional programming.

觀察 :在函數式編程中不鼓勵可變性。

We are modifying the global object. But how would we make it pure? Just return the value increased by 1.

我們正在修改全局對象。 但是,我們將如何使其pure呢? 只需返回增加1的值即可。

See that our pure function increaseCounter returns 2, but the counter value is still the same. The function returns the incremented value without altering the value of the variable.

看到我們的純函數increaseCounter返回2,但是counter值仍然相同。 該函數將返回增加的值,而不更改變量的值。

If we follow these two simple rules, it gets easier to understand our programs. Now every function is isolated and unable to impact other parts of our system.

如果我們遵循這兩個簡單的規則,就會更容易理解我們的程序。 現在,每個功能都是孤立的,無法影響系統的其他部分。

Pure functions are stable, consistent, and predictable. Given the same parameters, pure functions will always return the same result. We don’t need to think of situations when the same parameter has different results — because it will never happen.

純函數穩定,一致且可預測。 給定相同的參數,純函數將始終返回相同的結果。 我們不需要考慮相同參數產生不同結果的情況-因為它永遠不會發生。

純功能的好處 (Pure functions benefits)

The code’s definitely easier to test. We don’t need to mock anything. So we can unit test pure functions with different contexts:

該代碼絕對更容易測試。 我們不需要嘲笑任何東西。 因此,我們可以對具有不同上下文的純函數進行單元測試:

  • Given a parameter A → expect the function to return value B

    給定參數A →期望函數返回值B

  • Given a parameter C → expect the function to return value D

    給定參數C →期望函數返回值D

A simple example would be a function to receive a collection of numbers and expect it to increment each element of this collection.

一個簡單的示例是一個函數,該函數接收一個數字集合,并期望它增加該集合的每個元素。

let list = [1, 2, 3, 4, 5];const incrementNumbers = (list) => list.map(number => number + 1);

We receive the numbers array, use map to increment each number, and return a new list of incremented numbers.

我們收到numbers數組,使用map遞增每個數字,并返回一個新的遞增數字列表。

incrementNumbers(list); // [2, 3, 4, 5, 6]

For the input [1, 2, 3, 4, 5], the expected output would be [2, 3, 4, 5, 6].

對于input [1, 2, 3, 4, 5] ,預期output[2, 3, 4, 5, 6]

不變性 (Immutability)

Unchanging over time or unable to be changed.
隨時間不變或無法更改。

When data is immutable, its state cannot change after it’s created. If you want to change an immutable object, you can’t. Instead, you create a new object with the new value.

當數據是不可變的時,它的 狀態無法改變 創建之后。 如果要更改不可變對象,則不能。 代替, 您將使用新值創建一個新對象。

In JavaScript we commonly use the for loop. This next for statement has some mutable variables.

在JavaScript中,我們通常使用for循環。 接下來的for語句具有一些可變變量。

var values = [1, 2, 3, 4, 5];
var sumOfValues = 0;for (var i = 0; i < values.length; i++) {sumOfValues += values[i];
}sumOfValues // 15

For each iteration, we are changing the i and the sumOfValue state. But how do we handle mutability in iteration? Recursion.

對于每次迭代,我們都將更改isumOfValue狀態。 但是,我們如何處理迭代中的可變性呢? 遞歸。

let list = [1, 2, 3, 4, 5];
let accumulator = 0;function sum(list, accumulator) {if (list.length == 0) {return accumulator;}return sum(list.slice(1), accumulator + list[0]);
}sum(list, accumulator); // 15
list; // [1, 2, 3, 4, 5]
accumulator; // 0

So here we have the sum function that receives a vector of numerical values. The function calls itself until we get the list empty (our recursion base case). For each "iteration" we will add the value to the total accumulator.

因此,這里有sum函數,用于接收數值向量。 該函數將自行調用,直到列表為空( 遞歸base case )為止。 對于每個“迭代”,我們會將其值添加到total累加器中。

With recursion, we keep our variables immutable. The list and the accumulator variables are not changed. It keeps the same value.

通過遞歸,我們保留變量 一成不變的。 listaccumulator變量不變。 它保持相同的值。

Observation: We can use reduce to implement this function. We will cover this in the higher order functions topic.

觀察 :我們可以使用reduce來實現此功能。 我們將在高階函數主題中對此進行介紹。

It is also very common to build up the final state of an object. Imagine we have a string, and we want to transform this string into a url slug.

建立對象的最終狀態也很常見。 假設我們有一個字符串,并且我們想將此字符串轉換為url slug

In Object Oriented Programming in Ruby, we would create a class, let’s say, UrlSlugify. And this class will have a slugify method to transform the string input into a url slug.

在Ruby中的面向對象編程中,我們將創建一個類,例如UrlSlugify 。 此類將具有slugify方法,以將輸入的字符串轉換為url slug

class UrlSlugifyattr_reader :textdef initialize(text)@text = textenddef slugify!text.downcase!text.strip!text.gsub!(' ', '-')end
endUrlSlugify.new(' I will be a url slug   ').slugify! # "i-will-be-a-url-slug"

It’s implemented!

它實現了!

Here we have imperative programming saying exactly what we want to do in each slugify process — first lower-case, then remove useless white spaces and, finally, replace remaining white spaces with hyphens.

在這里,我們必須進行命令式編程,確切地說出每個slugify處理中要執行的操作-首先小寫字母,然后刪除無用的空格,最后用連字符替換其余的空格。

But we are mutating the input state in this process.

但是我們在這個過程中正在改變輸入狀態。

We can handle this mutation by doing function composition, or function chaining. In other words, the result of a function will be used as an input for the next function, without modifying the original input string.

我們可以通過執行功能組合或功能鏈接來處理此突變。 換句話說,函數的結果將用作下一個函數的輸入,而無需修改原始輸入字符串。

const string = " I will be a url slug   ";const slugify = string =>string.toLowerCase().trim().split(" ").join("-");slugify(string); // i-will-be-a-url-slug

Here we have:

這里有:

  • toLowerCase: converts the string to all lower case

    toLowerCase :將字符串轉換為所有小寫

  • trim: removes white-space from both ends of a string

    trim :刪除字符串兩端的空白

  • split and join: replaces all instances of match with replacement in a given string

    split and join :用給定字符串中的替換替換所有match實例

We combine all these 4 functions and we can "slugify" our string.

我們將所有這四個函數結合在一起,就可以"slugify"字符串了。

參照透明 (Referential transparency)

Let’s implement a square function:

讓我們實現一個square function

const square = (n) => n * n;

This pure function will always have the same output, given the same input.

給定相同的輸入,此純函數將始終具有相同的輸出。

square(2); // 4
square(2); // 4
square(2); // 4
// ...

Passing 2 as a parameter of the square function will always returns 4. So now we can replace the square(2) with 4. Our function is referentially transparent.

傳遞2作為square function的參數將始終返回4。因此,現在我們可以將square(2)替換為4。我們的函數是referentially transparent

Basically, if a function consistently yields the same result for the same input, it is referentially transparent.

基本上,如果一個函數對于相同的輸入始終產生相同的結果,則它是參照透明的。

pure functions + immutable data = referential transparency

純函數+不可變數據=參考透明

With this concept, a cool thing we can do is to memoize the function. Imagine we have this function:

有了這個概念,我們可以做的一件很酷的事情就是記住該功能。 想象一下我們具有以下功能:

const sum = (a, b) => a + b;

And we call it with these parameters:

我們用以下參數調用它:

sum(3, sum(5, 8));

The sum(5, 8) equals 13. This function will always result in 13. So we can do this:

sum(5, 8)等于13 。 此功能將始終導致13 。 因此,我們可以這樣做:

sum(3, 13);

And this expression will always result in 16. We can replace the entire expression with a numerical constant and memoize it.

這個表達式將始終為16 。 我們可以將整個表達式替換為數字常量并進行記憶 。

作為一流實體 (Functions as first-class entities)

The idea of functions as first-class entities is that functions are also treated as values and used as data.

函數作為一等實體的想法是將函數也視為值并用作數據。

Functions as first-class entities can:

作為一流實體的功能可以:

  • refer to it from constants and variables

    從常量和變量中引用它
  • pass it as a parameter to other functions

    將其作為參數傳遞給其他函數
  • return it as result from other functions

    作為其他函數的結果返回

The idea is to treat functions as values and pass functions like data. This way we can combine different functions to create new functions with new behavior.

這個想法是將函數視為值,并像數據一樣傳遞函數。 這樣,我們可以組合不同的功能以創建具有新行為的新功能。

Imagine we have a function that sums two values and then doubles the value. Something like this:

想象一下,我們有一個將兩個值相加然后將值加倍的函數。 像這樣:

const doubleSum = (a, b) => (a + b) * 2;

Now a function that subtracts values and the returns the double:

現在,一個減去值并返回雙精度值的函數:

const doubleSubtraction = (a, b) => (a - b) * 2;

These functions have similar logic, but the difference is the operators functions. If we can treat functions as values and pass these as arguments, we can build a function that receives the operator function and use it inside our function.

這些功能具有相似的邏輯,但是區別在于運算符功能。 如果我們可以將函數視為值并將其作為參數傳遞,則可以構建一個接收操作符函數并在函數內部使用的函數。

const sum = (a, b) => a + b;
const subtraction = (a, b) => a - b;const doubleOperator = (f, a, b) => f(a, b) * 2;doubleOperator(sum, 3, 1); // 8
doubleOperator(subtraction, 3, 1); // 4

Now we have an f argument, and use it to process a and b. We passed the sum and subtraction functions to compose with the doubleOperator function and create a new behavior.

現在我們有一個f參數,并用它來處理ab 。 我們傳遞了sumsubtraction函數來與doubleOperator函數組合并創建新行為。

高階函數 (Higher-order functions)

When we talk about higher-order functions, we mean a function that either:

當我們談論高階函數時,我們指的是以下函數之一:

  • takes one or more functions as arguments, or

    將一個或多個函數作為參數,或
  • returns a function as its result

    返回一個函數作為其結果

The doubleOperator function we implemented above is a higher-order function because it takes an operator function as an argument and uses it.

我們上面實現的doubleOperator函數是一個高階函數,因為它將運算符作為參數并使用它。

You’ve probably already heard about filter, map, and reduce. Let's take a look at these.

您可能已經聽說過filtermapreduce 。 讓我們來看看這些。

過濾 (Filter)

Given a collection, we want to filter by an attribute. The filter function expects a true or false value to determine if the element should or should not be included in the result collection. Basically, if the callback expression is true, the filter function will include the element in the result collection. Otherwise, it will not.

給定一個集合,我們想按屬性過濾。 過濾器函數期望使用truefalse值來確定是否應將元素包含在結果集合中。 基本上,如果回調表達式為true ,則過濾器函數會將元素包括在結果集合中。 否則,它將不會。

A simple example is when we have a collection of integers and we want only the even numbers.

一個簡單的例子是當我們有一個整數集合并且我們只需要偶數時。

勢在必行 (Imperative approach)

An imperative way to do it with JavaScript is to:

使用JavaScript的一種必要方法是:

  • create an empty array evenNumbers

    創建一個空數組evenNumbers

  • iterate over the numbers array

    遍歷numbers數組

  • push the even numbers to the evenNumbers array

    將偶數推送到evenNumbers數組

var numbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
var evenNumbers = [];for (var i = 0; i < numbers.length; i++) {if (numbers[i] % 2 == 0) {evenNumbers.push(numbers[i]);}
}console.log(evenNumbers); // (6) [0, 2, 4, 6, 8, 10]

We can also use the filter higher order function to receive the even function, and return a list of even numbers:

我們還可以使用filter高階函數來接收even函數,并返回偶數列表:

const even = n => n % 2 == 0;
const listOfNumbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
listOfNumbers.filter(even); // [0, 2, 4, 6, 8, 10]

One interesting problem I solved on Hacker Rank FP Path was the Filter Array problem. The problem idea is to filter a given array of integers and output only those values that are less than a specified value X.

我在Hacker Rank FP路徑上解決的一個有趣的問題是“ 過濾器陣列”問題 。 問題的思想是過濾給定的整數數組,僅輸出小于指定值X那些值。

An imperative JavaScript solution to this problem is something like:

解決此問題的強制性JavaScript解決方案如下:

var filterArray = function(x, coll) {var resultArray = [];for (var i = 0; i < coll.length; i++) {if (coll[i] < x) {resultArray.push(coll[i]);}}return resultArray;
}console.log(filterArray(3, [10, 9, 8, 2, 7, 5, 1, 3, 0])); // (3) [2, 1, 0]

We say exactly what our function needs to do — iterate over the collection, compare the collection current item with x, and push this element to the resultArray if it pass the condition.

我們確切地說出函數需要做的事情–遍歷集合,將集合當前項與x進行比較,如果該元素通過條件,則將其推送到resultArray

聲明式方法 (Declarative approach)

But we want a more declarative way to solve this problem, and using the filter higher order function as well.

但是,我們需要一種更具聲明性的方式來解決此問題,并且還需要使用filter高階函數。

A declarative JavaScript solution would be something like this:

聲明性JavaScript解決方案如下所示:

function smaller(number) {return number < this;
}function filterArray(x, listOfNumbers) {return listOfNumbers.filter(smaller, x);
}let numbers = [10, 9, 8, 2, 7, 5, 1, 3, 0];filterArray(3, numbers); // [2, 1, 0]

Using this in the smaller function seems a bit strange in the first place, but is easy to understand.

首先,在smaller函數中使用this函數似乎有些奇怪,但很容易理解。

this will be the second parameter in the filter function. In this case, 3 (the x) is represented by this. That's it.

this將是filter功能中的第二個參數。 在這種情況下, 3 ( x )表示為this 。 而已。

We can also do this with maps. Imagine we have a map of people with their name and age.

我們也可以使用地圖來做到這一點。 想象一下,我們有一幅地圖,上面有他們的nameage

let people = [{ name: "TK", age: 26 },{ name: "Kaio", age: 10 },{ name: "Kazumi", age: 30 }
];

And we want to filter only people over a specified value of age, in this example people who are more than 21 years old.

而且,我們只希望過濾特定年齡段的人員,在此示例中,年齡超過21歲的人員。

const olderThan21 = person => person.age > 21;
const overAge = people => people.filter(olderThan21);
overAge(people); // [{ name: 'TK', age: 26 }, { name: 'Kazumi', age: 30 }]

Summary of code:

代碼摘要:

  • we have a list of people (with name and age).

    我們有一個人的名單( nameage )。

  • we have a function olderThan21. In this case, for each person in people array, we want to access the age and see if it is older than 21.

    我們有一個功能olderThan21 。 在這種情況下,對于人員數組中的每個人,我們要訪問age并查看age是否大于21歲。

  • we filter all people based on this function.

    我們基于此功能過濾所有人員。

地圖 (Map)

The idea of map is to transform a collection.

map的想法是轉換集合。

The map method transforms a collection by applying a function to all of its elements and building a new collection from the returned values.

map方法通過將函數應用于其所有元素并根據返回的值構建新集合來轉換集合。

Let’s get the same people collection above. We don't want to filter by “over age” now. We just want a list of strings, something like TK is 26 years old. So the final string might be :name is :age years old where :name and :age are attributes from each element in the people collection.

讓我們得到上面的同一people集合。 我們現在不想按“年齡超過”進行過濾。 我們只想要一個字符串列表,例如TK is 26 years old 。 因此,最后一個字符串可能是:name is :age years old ,其中:name:agepeople集合中每個元素的屬性。

In a imperative JavaScript way, it would be:

用命令式JavaScript方式,它將是:

var people = [{ name: "TK", age: 26 },{ name: "Kaio", age: 10 },{ name: "Kazumi", age: 30 }
];var peopleSentences = [];for (var i = 0; i < people.length; i++) {var sentence = people[i].name + " is " + people[i].age + " years old";peopleSentences.push(sentence);
}console.log(peopleSentences); // ['TK is 26 years old', 'Kaio is 10 years old', 'Kazumi is 30 years old']

In a declarative JavaScript way, it would be:

用聲明性JavaScript方式,它將是:

const makeSentence = (person) => `${person.name} is ${person.age} years old`;const peopleSentences = (people) => people.map(makeSentence);peopleSentences(people);
// ['TK is 26 years old', 'Kaio is 10 years old', 'Kazumi is 30 years old']

The whole idea is to transform a given array into a new array.

整個想法是將給定的數組轉換為新的數組。

Another interesting Hacker Rank problem was the update list problem. We just want to update the values of a given array with their absolute values.

另一個有趣的Hacker Rank問題是更新列表問題 。 我們只想用其絕對值更新給定數組的值。

For example, the input [1, 2, 3, -4, 5]needs the output to be [1, 2, 3, 4, 5]. The absolute value of -4 is 4.

例如,輸入[1, 2, 3, -4, 5]需要將輸出為[1, 2, 3, 4, 5]-4的絕對值為4

A simple solution would be an in-place update for each collection value.

一個簡單的解決方案是就每個集合值進行就地更新。

var values = [1, 2, 3, -4, 5];for (var i = 0; i < values.length; i++) {values[i] = Math.abs(values[i]);
}console.log(values); // [1, 2, 3, 4, 5]

We use the Math.abs function to transform the value into its absolute value, and do the in-place update.

我們使用Math.abs函數將值轉換為其絕對值,并進行就地更新。

This is not a functional way to implement this solution.

不是實現此解決方案的功能方法。

First, we learned about immutability. We know how immutability is important to make our functions more consistent and predictable. The idea is to build a new collection with all absolute values.

首先,我們了解了不變性。 我們知道不變性對于使我們的功能更加一致和可預測是多么重要。 這個想法是建立一個具有所有絕對值的新集合。

Second, why not use map here to "transform" all data?

其次,為什么不使用map來“轉換”所有數據?

My first idea was to test the Math.abs function to handle only one value.

我的第一個想法是測試Math.abs函數以僅處理一個值。

Math.abs(-1); // 1
Math.abs(1); // 1
Math.abs(-2); // 2
Math.abs(2); // 2

We want to transform each value into a positive value (the absolute value).

我們希望將每個值轉換為正值(絕對值)。

Now that we know how to do absolute for one value, we can use this function to pass as an argument to the map function. Do you remember that a higher order function can receive a function as an argument and use it? Yes, map can do it!

現在我們知道如何對一個值進行absolute運算,我們可以使用此函數作為參數傳遞給map函數。 您還記得higher order function可以將函數作為參數來使用嗎? 是的,地圖可以做到!

let values = [1, 2, 3, -4, 5];const updateListMap = (values) => values.map(Math.abs);updateListMap(values); // [1, 2, 3, 4, 5]

Wow. So beautiful!

哇。 如此美麗!

減少 (Reduce)

The idea of reduce is to receive a function and a collection, and return a value created by combining the items.

reduce的想法是接收一個函數和一個集合,并返回通過組合項目創建的值。

A common example people talk about is to get the total amount of an order. Imagine you were at a shopping website. You’ve added Product 1, Product 2, Product 3, and Product 4 to your shopping cart (order). Now we want to calculate the total amount of the shopping cart.

人們談論的一個常見示例是獲取訂單的總金額。 想象一下您在一個購物網站上。 您已將Product 1Product 2Product 3Product 4到購物車(訂單)。 現在,我們要計算購物車的總金額。

In imperative way, we would iterate the order list and sum each product amount to the total amount.

以命令方式,我們將迭代訂單清單,并將每個產品的數量加總到總數量。

var orders = [{ productTitle: "Product 1", amount: 10 },{ productTitle: "Product 2", amount: 30 },{ productTitle: "Product 3", amount: 20 },{ productTitle: "Product 4", amount: 60 }
];var totalAmount = 0;for (var i = 0; i < orders.length; i++) {totalAmount += orders[i].amount;
}console.log(totalAmount); // 120

Using reduce, we can build a function to handle the amount sum and pass it as an argument to the reduce function.

使用reduce ,我們可以構建一個函數來處理amount sum并將其作為參數傳遞給reduce函數。

let shoppingCart = [{ productTitle: "Product 1", amount: 10 },{ productTitle: "Product 2", amount: 30 },{ productTitle: "Product 3", amount: 20 },{ productTitle: "Product 4", amount: 60 }
];const sumAmount = (currentTotalAmount, order) => currentTotalAmount + order.amount;const getTotalAmount = (shoppingCart) => shoppingCart.reduce(sumAmount, 0);getTotalAmount(shoppingCart); // 120

Here we have shoppingCart, the function sumAmount that receives the current currentTotalAmount , and the order object to sum them.

在這里,我們有shoppingCart ,接收當前currentTotalAmount的功能sumAmount以及用于對它們sumorder對象。

The getTotalAmount function is used to reduce the shoppingCart by using the sumAmount and starting from 0.

getTotalAmount函數用于通過使用sumAmount并從0開始reduce shoppingCart sumAmount

Another way to get the total amount is to compose map and reduce. What do I mean by that? We can use map to transform the shoppingCart into a collection of amount values, and then just use the reduce function with sumAmount function.

獲得總量的另一種方法是組成mapreduce 。 那是什么意思 我們可以使用mapshoppingCart轉換為amount值的集合,然后僅將reduce函數與sumAmount函數一起使用。

const getAmount = (order) => order.amount;
const sumAmount = (acc, amount) => acc + amount;function getTotalAmount(shoppingCart) {return shoppingCart.map(getAmount).reduce(sumAmount, 0);
}getTotalAmount(shoppingCart); // 120

The getAmount receives the product object and returns only the amount value. So what we have here is [10, 30, 20, 60]. And then the reduce combines all items by adding up. Beautiful!

getAmount接收產品對象,并且僅返回amount值。 所以我們這里是[10, 30, 20, 60] 。 然后reduce將所有項目相加在一起。 美麗!

We took a look at how each higher order function works. I want to show you an example of how we can compose all three functions in a simple example.

我們看了每個高階函數如何工作。 我想向您展示一個示例,說明如何在一個簡單的示例中組合所有三個函數。

Talking about shopping cart, imagine we have this list of products in our order:

談論shopping cart ,想象一下我們的訂單中有以下產品清單:

let shoppingCart = [{ productTitle: "Functional Programming", type: "books", amount: 10 },{ productTitle: "Kindle", type: "eletronics", amount: 30 },{ productTitle: "Shoes", type: "fashion", amount: 20 },{ productTitle: "Clean Code", type: "books", amount: 60 }
]

We want the total amount of all books in our shopping cart. Simple as that. The algorithm?

我們需要購物車中所有書籍的總數。 就那么簡單。 算法?

  • filter by book type

    按書籍類型過濾
  • transform the shopping cart into a collection of amount using map

    使用地圖將購物車轉化為金額集合
  • combine all items by adding them up with reduce

    通過將所有項目與reduce相加來合并
let shoppingCart = [{ productTitle: "Functional Programming", type: "books", amount: 10 },{ productTitle: "Kindle", type: "eletronics", amount: 30 },{ productTitle: "Shoes", type: "fashion", amount: 20 },{ productTitle: "Clean Code", type: "books", amount: 60 }
]const byBooks = (order) => order.type == "books";
const getAmount = (order) => order.amount;
const sumAmount = (acc, amount) => acc + amount;function getTotalAmount(shoppingCart) {return shoppingCart.filter(byBooks).map(getAmount).reduce(sumAmount, 0);
}getTotalAmount(shoppingCart); // 70

Done!

做完了!

資源資源 (Resources)

I’ve organised some resources I read and studied. I’m sharing the ones that I found really interesting. For more resources, visit my Functional Programming Github repository

我整理了一些閱讀和學習的資源。 我正在分享我發現非常有趣的內容。 有關更多資源,請訪問我的Functional Programming Github存儲庫

  • EcmaScript 6 course by Wes Bos

    Wes Bos的EcmaScript 6課程

  • JavaScript by OneMonth

    JavaScript by OneMonth

  • Ruby specific resources

    Ruby專用資源

  • Javascript specific resources

    Javascript專用資源

  • Clojure specific resources

    Clojure特定資源

  • Learn React by building an App

    通過構建應用來學習React

簡介 (Intros)

  • Learning FP in JS

    在JS中學習FP

  • Intro do FP with Python

    用Python介紹FP

  • Overview of FP

    FP概述

  • A quick intro to functional JS

    功能性JS快速入門

  • What is FP?

    什么是FP?

  • Functional Programming Jargon

    函數式編程術語

純功能 (Pure functions)

  • What is a pure function?

    什么是純函數?

  • Pure Functional Programming 1

    純函數式編程1

  • Pure Functional Programming 2

    純函數式編程2

不變的數據 (Immutable data)

  • Immutable DS for functional programming

    用于功能編程的不可變DS

  • Why shared mutable state is the root of all evil

    為什么共有的可變狀態是萬惡之源

高階函數 (Higher-order functions)

  • Eloquent JS: Higher Order Functions

    雄辯的JS:高階函數

  • Fun fun function Filter

    趣味功能過濾器

  • Fun fun function Map

    趣味功能圖

  • Fun fun function Basic Reduce

    趣味功能基本減少

  • Fun fun function Advanced Reduce

    趣味功能高級減少

  • Clojure Higher Order Functions

    Clojure高階函數

  • Purely Function Filter

    純功能過濾器

  • Purely Functional Map

    純功能圖

  • Purely Functional Reduce

    純功能減少

聲明式編程 (Declarative Programming)

  • Declarative Programming vs Imperative

    聲明式編程與命令式

而已! (That’s it!)

Hey people, I hope you had fun reading this post, and I hope you learned a lot here! This was my attempt to share what I’m learning.

大家好,我希望您在閱讀這篇文章時玩得開心,希望您在這里學到了很多東西! 這是我分享自己所學知識的嘗試。

Here is the repository with all codes from this article.

這是本文中所有代碼的存儲庫 。

Come learn with me. I’m sharing resources and my code in this Learning Functional Programming repository.

來跟我學習。 我正在這個“ 學習功能編程”存儲庫中共享資源和代碼。

I also wrote an FP post but using mainly Clojure

我還寫了一篇FP帖子,但主要使用Clojure

I hope you saw something useful to you here. And see you next time! :)

希望您在這里看到了對您有用的東西。 下次見! :)

My Twitter & Github.

我的Twitter和Github 。

TK.

TK。

翻譯自: https://www.freecodecamp.org/news/functional-programming-principles-in-javascript-1b8fc6c3563f/

javascript函數式

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/392462.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/392462.shtml
英文地址,請注明出處:http://en.pswp.cn/news/392462.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

java writeint_Java DataOutputStream.writeInt(int v)類型

DataOutputStream.writeInt(int v)方法示例DataOutputStream的DataOutputStream.writeInt(int v)方法具有以下語法。public final void writeInt(int v) throws IOException示例在下面的代碼中展示了如何使用DataOutputStream.writeInt(int v)方法。import java.io.DataInputSt…

協方差意味著什么_“零”到底意味著什么?

協方差意味著什么When I was an undergraduate student studying Data Science, one of my professors always asked the same question for every data set we worked with — “What does zero mean?”當我是一名研究數據科學的本科生時&#xff0c;我的一位教授總是對我們處…

Go_筆試題記錄-不熟悉的

1、golang中沒有隱藏的this指針&#xff0c;這句話的含義是&#xff08;&#xff09; A. 方法施加的對象顯式傳遞&#xff0c;沒有被隱藏起來 B. golang沿襲了傳統面向對象編程中的諸多概念&#xff0c;比如繼承、虛函數和構造函數 C. golang的面向對象表達更直觀&#xff0c;對…

leetcode 316. 去除重復字母(單調棧)

給你一個字符串 s &#xff0c;請你去除字符串中重復的字母&#xff0c;使得每個字母只出現一次。需保證 返回結果的字典序最小&#xff08;要求不能打亂其他字符的相對位置&#xff09;。 注意&#xff1a;該題與 1081 https://leetcode-cn.com/problems/smallest-subsequenc…

Go-json解碼到結構體

廢話不多說&#xff0c;直接干就得了&#xff0c;上代碼 package mainimport ("encoding/json""fmt" )type IT struct {Company string json:"company" Subjects []string json:"subjects"IsOk bool json:"isok"…

leetcode 746. 使用最小花費爬樓梯(dp)

數組的每個索引作為一個階梯&#xff0c;第 i個階梯對應著一個非負數的體力花費值 costi。 每當你爬上一個階梯你都要花費對應的體力花費值&#xff0c;然后你可以選擇繼續爬一個階梯或者爬兩個階梯。 您需要找到達到樓層頂部的最低花費。在開始時&#xff0c;你可以選擇從索…

安卓中經常使用控件遇到問題解決方法(持續更新和發現篇幅)(在textview上加一條線、待續)...

TextView設置最多顯示30個字符。超過部分顯示...(省略號)&#xff0c;有人說分別設置TextView的android:signature"true",而且設置android:ellipsize"end";可是我試了。居然成功了&#xff0c;供大家參考 [java] view plaincopy<TextView android:id…

網絡工程師晉升_晉升為工程師的最快方法

網絡工程師晉升by Sihui Huang黃思慧 晉升為工程師的最快方法 (The Fastest Way to Get Promoted as an Engineer) We all want to live up to our potential, grow in our career, and do the best work of our lives. Getting promoted at work not only proves that we hav…

java 銀行存取款_用Java編寫銀行存錢取錢

const readline require(‘readline-sync‘)//引用readline-synclet s 2;//錯誤的次數for (let i 0; i < 3; i) {console.log(‘請輸入名&#xff1a;(由英文組成)‘);let user readline.question();console.log(‘請輸入密碼&#xff1a;(由數字組成)‘);let password …

垃圾郵件分類 python_在python中創建SMS垃圾郵件分類器

垃圾郵件分類 python介紹 (Introduction) I have always been fascinated with Google’s gmail spam detection system, where it is able to seemingly effortlessly judge whether incoming emails are spam and therefore not worthy of our limited attention.我一直對Goo…

leetcode 103. 二叉樹的鋸齒形層序遍歷(層序遍歷)

給定一個二叉樹&#xff0c;返回其節點值的鋸齒形層序遍歷。&#xff08;即先從左往右&#xff0c;再從右往左進行下一層遍歷&#xff0c;以此類推&#xff0c;層與層之間交替進行&#xff09;。例如&#xff1a; 給定二叉樹 [3,9,20,null,null,15,7],3/ \9 20/ \15 7 返回…

簡單易用的MongoDB

從我第一次聽到Nosql這個概念到如今已經走過4個年頭了&#xff0c;但仍然沒有具體的去做過相應的實踐。最近獲得一段學習休息時間&#xff0c;購買了Nosql技術實踐一書&#xff0c;正在慢慢的學習。在主流觀點中&#xff0c;Nosql大體分為4類&#xff0c;鍵值存儲數據庫&#x…

html畫布圖片不顯示_如何在HTML5畫布上顯示圖像

html畫布圖片不顯示by Nash Vail由Nash Vail Ok, so here’s a question: “Why do we need an article for this, Nash?”好的&#xff0c;這是一個問題&#xff1a;“為什么我們需要為此寫一篇文章&#xff0c;納什&#xff1f;” Well, grab a seat.好吧&#xff0c;坐下…

java斷點續傳插件_視頻斷點續傳+java視頻

之前仿造uploadify寫了一個HTML5版的文件上傳插件&#xff0c;沒看過的朋友可以點此先看一下~得到了不少朋友的好評&#xff0c;我自己也用在了項目中&#xff0c;不論是用戶頭像上傳&#xff0c;還是各種媒體文件的上傳&#xff0c;以及各種個性的業務需求&#xff0c;都能得到…

全棧入門_啟動數據棧入門包(2020)

全棧入門I advise a lot of people on how to build out their data stack, from tiny startups to enterprise companies that are moving to the cloud or from legacy solutions. There are many choices out there, and navigating them all can be tricky. Here’s a brea…

Go-json解碼到接口及根據鍵獲取值

Go-json解碼到接口及根據鍵獲取值 package mainimport ("encoding/json""fmt""github.com/bitly/go-simplejson" )type JsonServer struct {ServerName stringServerIP string }type JsonServers struct {Servers []JsonServer }func main() {…

C#接口的顯隱實現

顯示接口實現與隱式接口實現 何為顯式接口實現、隱式接口實現&#xff1f;簡單概括&#xff0c;使用接口名作為方法名的前綴&#xff0c;這稱為“顯式接口實現”&#xff1b;傳統的實現方式&#xff0c;稱為“隱式接口實現”。下面給個例子。 IChineseGreeting接口&#xff0c;…

亞馬遜 各國站點 鏈接_使用Amazon S3和HTTPS的簡單站點托管

亞馬遜 各國站點 鏈接by Georgia Nola喬治亞諾拉(Georgia Nola) 使用Amazon S3和HTTPS的簡單站點托管 (Simple site hosting with Amazon S3 and HTTPS) Hiya folks!大家好&#xff01; In this tutorial I’ll show you how to host a static website with HTTPS on AWS wit…

leetcode 387. 字符串中的第一個唯一字符(hash)

給定一個字符串&#xff0c;找到它的第一個不重復的字符&#xff0c;并返回它的索引。如果不存在&#xff0c;則返回 -1。 示例&#xff1a; s “leetcode” 返回 0 s “loveleetcode” 返回 2 class Solution { public int firstUniqChar(String s) { int[][] tempnew i…

marlin 三角洲_三角洲湖泊和數據湖泊-入門

marlin 三角洲Data lakes are becoming adopted in more and more companies seeking for efficient storage of their assets. The theory behind it is quite simple, in contrast to the industry standard data warehouse. To conclude this this post explains the logica…