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.
(通過一些調(diào)查潜腻,我發(fā)現(xiàn)函數(shù)式編程的概念像是不可變以及純函數(shù)方法。這些概念能使你建立沒有副作用的函數(shù)社裆,因此很容易去管理系統(tǒng)制市,還有一些好處)
what is functional programming?
Function 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.
how do we know if a function is pure or not? Here is a very strict definition od purity(怎么去判斷一個函數(shù)是不是純函數(shù)):
- It return the same result if given the same arguments(it is also referred as deterministic)(同樣的輸入得到同樣的輸出-確定性)
- It does not cause any observable side effects(不會引起任何明顯的副作用)
It returns the same result if given the same arguments
let PI = 3.14;
const calculateArea = (radius) => radius * radius * PI;
calculateArea(10); // returns 314.0
Observation: mutability is discouraged in functional programming.(可變性在函數(shù)式編程中是不鼓勵的)
let counter = 1;
function increaseCounter(value) {
counter = value + 1;
}
increaseCounter(counter);
console.log(counter); // 2
How would we make it pure?(怎么使他編程存函數(shù))
let counter = 1;
function increaseCounter(value) {
counter = value + 1;
}
increaseCounter(counter);
console.log(counter); // 2
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.(純函數(shù)是穩(wěn)定的,唯一的和可預(yù)測的渗磅,給與相同的參數(shù)犯眠,純函數(shù)將總是返回相同的結(jié)果按灶。我們不需要考慮當(dāng)參數(shù)相同,結(jié)果不相同的場景筐咧,因?yàn)檫@絕對不會發(fā)生)
pure functions benefits(純函數(shù)的好處)
The code's definitely easier to test.(該代碼絕對易于測試)
let list = [1, 2, 3, 4, 5];
const incrementNumbers = (list) => list.map(number => number + 1);
incrementNumbers(list); // [2, 3, 4, 5, 6]
Immutability
Unchanging over time or unable to be changed.
Wen 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.(當(dāng)數(shù)據(jù)是不可變的鸯旁,在創(chuàng)建的時(shí)候,他的狀態(tài)是不能變化量蕊,你絕不能改變一個不可變的對象铺罢,你可以用新值創(chuàng)建一個新對象)
var values = [1, 2, 3, 4, 5];
var sumOfValues = 0;
for (var i = 0; i < values.length; i++) {
sumOfValues += values[I];
}
sumOfValues // 15
How do we handle mutability in iteration? Recursion.(我們?nèi)绾翁幚淼械目勺冃裕窟f歸残炮。)
let list = [1,2,3,4,5]
let accumulator = 0;
function sum(list, accumulator) {
if(!list.length) {
return accumulator;
}
return sum(list.splice(1), accumulator + list[0])
}
sum(list, accumulator); // 15
list; // [1, 2, 3, 4, 5]
accumulator; // 0
Observation: We can use reduce to implement this function.(我們能用 reduce 來實(shí)現(xiàn)這個函數(shù))
let list = [1,2,3,4,5]
let accumulator = 0;
function sum(list, accumulator) {
return list.reduce((accumulator_Q, current) => {
return accumulator_Q + current
})
}
sum(list, accumulator); // 15
list; // [1, 2, 3, 4, 5]
accumulator; // 0
const string = " I will be a url slug ";
const slugify = string =>
string
.toLowerCase()
.trim()
.split(" ")
.join("-");
slugify(string); // i-will-be-a-url-slug
Referential transparency(參照透明)
const sum = (a, b) => a + b;
sum(3, sum(5, 8));
functions as first-class entities (函數(shù)是一等公民)
Function as first-class entities can:
- refer to it from constants and variables(從常量和變量中引用它)
- pass it as a parameter to other functions(作為參數(shù)傳遞給其他函數(shù))
- return it as result from other functions(從其他函數(shù)作為結(jié)果返回)
This idea is treat functions as values and pass functions like data. This way we can combine different functions to create new functions with new behavior.(這個想法是將函數(shù)視為值韭赘,并將函數(shù)作為數(shù)據(jù)傳遞。這樣势就,我們可以組合不同的功能來創(chuàng)建具有新行為的新功能泉瞻。)
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
filter
Syntax
var newArray = arr.filter(callback(element[, index[, array]])[, thisArg])
Parameters
- callback: Function is a predicate, to test each element of the array. Return true to keep the element, false otherwise. It accepts three arguments:
- element: The current element being processed in the array.
- index | Optional: The index of the current element being processed in the array.
- array | Optional: The array filter was called upon.
- thisArg | Optional: Value to use as this when executing callback.
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]
const even = num => num % 2 === 0
const listOfNumbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
listOfNumbers.filter(even)
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]
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);
map
The map method transforms a collection by applying a function to all of its elements and building a new collections from the returned values.(map方法通過將函數(shù)應(yīng)用于其所有元素并根據(jù)返回的值構(gòu)建新的集合來轉(zhuǎn)換集合。)
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']
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']
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]
let values = [1, 2, 3, -4, 5];
const updateListMap = (values) => values.map(Math.abs);
updateListMap(values); // [1, 2, 3, 4, 5]
reduce
The idea of reduce is to receive a function and a collection, and return a value created by combining the items.(reduce的想法是接收一個函數(shù)和一個集合苞冯,并返回通過組合項(xiàng)目創(chuàng)建的值袖牙。)
Syntax
arr.reduce(callback(accumulator, currentValue[, index[, array]])[, initialValue])
Parameters
- callback: A function to execute on each element in the array (except for the first, if no initialValue is supplied), taking four arguments(在數(shù)組中的每個元素上執(zhí)行的函數(shù)(第一個元素除外,如果未提供initialValue的話)舅锄,帶有四個參數(shù):):
- accumulator: The accumulator accumulates the callback's return values. It is the accumulated value previously returned in the last invocation of the callback, or initialValue, if supplied (see below).
- currentValue: The current element being processed in the array.
- index | Optional: The index of the current element being processed in the array. Starts from index 0 if an initialValue is provided. Otherwise, starts from index 1.
- array | Optional: The array reduce() was called upon.
- initialValue | Optional: A value to use as the first argument to the first call of the callback. If no initialValue is supplied, the first element in the array will be used and skipped. Calling reduce() on an empty array without an initialValue will throw a TypeError.
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
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
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.(獲得總量的另一種方法是組合 map 并進(jìn)行 reduce鞭达。那是什么意思我們可以使用map 將 shoppingCart 轉(zhuǎn)換為金額值的集合,然后僅將 reduce 函數(shù)與 sumAmount 函數(shù)一起使用巧娱。)
const getAmount = (order) => order.amount;
const sumAmount = (acc, amount) => acc + amount;
function getTotalAmount(shoppingCart) {
return shoppingCart
.map(getAmount)
.reduce(sumAmount, 0);
}
getTotalAmount(shoppingCart); // 120