├── .gitignore ├── README.md ├── examples.js ├── package.json └── translations ├── pt-BR └── README.md └── zh-CN └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## JavaScript Functional Programming Cookbook (ES6) 2 | A Cookbook for writing FP in JavaScript using ES6 3 | 4 | **Translations** 5 | 6 | - [Português (Brasil)](/translations/pt-BR/README.md) 7 | - [简体中文](/translations/zh-CN/README.md) 8 | 9 | ### Summary 10 | 11 | * [Pure functions](#pure-functions) 12 | * [Higher-order functions](#higher-order-functions) 13 | * [Recursion](#recursion) 14 | * [Functor](#functor) 15 | * [Compose](#compose) 16 | * [Destructuring](#destructuring) 17 | * [Currying](#currying) 18 | 19 | ### Pure functions 20 | Returns the same result given same parameters. It's execution doesn't depend on the state of the system. 21 | 22 | 1) Impure 23 | 24 | ```javascript 25 | let number = 1; 26 | 27 | const increment = () => number += 1; 28 | 29 | increment(); 30 | // 2 31 | ``` 32 | 33 | 2) Pure 34 | 35 | ```javascript 36 | const increment = n => n + 1; 37 | 38 | increment(1); 39 | // 2 40 | ``` 41 | 42 | ### Higher-order functions 43 | Functions that operate on other functions, either by taking them as arguments or by returning them. 44 | 45 | 1) Sum 46 | 47 | ```javascript 48 | const sum = (x, y) => x + y; 49 | 50 | const calculate = (fn, x, y) => fn(x, y); 51 | 52 | calculate(sum, 1, 2); 53 | // 3 54 | ``` 55 | 56 | 2) Filter 57 | 58 | ```javascript 59 | let students = [ 60 | {name: 'Anna', grade: 6}, 61 | {name: 'John', grade: 4}, 62 | {name: 'Maria', grade: 9} 63 | ]; 64 | 65 | const isApproved = student => student.grade >= 6; 66 | 67 | students.filter(isApproved); 68 | // [ { name: 'Anna', grade: 6 }, { name: 'Maria', grade: 9 } ] 69 | ``` 70 | 71 | 3) Map 72 | 73 | ```javascript 74 | const byName = obj => obj.name; 75 | 76 | students.map(byName); 77 | // [ 'Anna', 'John', 'Maria' ] 78 | ``` 79 | 80 | 4) Chaining 81 | 82 | ```javascript 83 | let students = [ 84 | {name: 'Anna', grade: 6}, 85 | {name: 'John', grade: 4}, 86 | {name: 'Maria', grade: 9} 87 | ]; 88 | 89 | const isApproved = student => student.grade >= 6; 90 | 91 | const byName = obj => obj.name; 92 | 93 | students.filter(isApproved).map(byName); 94 | // ['Anna', 'Maria'] 95 | ``` 96 | 97 | 5) Reduce 98 | 99 | ```javascript 100 | const totalGrades = students.reduce((sum, student) => sum + student.grade, 0); 101 | 102 | totalGrades 103 | // 19 104 | ``` 105 | 106 | ### Recursion 107 | Whenever a function calls itself, creating a loop. 108 | 109 | 1) Countdown 110 | 111 | ```javascript 112 | 113 | const countdown = num => { 114 | console.log(num) 115 | num < 1 116 | ? num 117 | : countdown(num - 1) 118 | } 119 | 120 | countdown(5); 121 | /* 122 | 5 123 | 4 124 | 3 125 | 2 126 | 1 127 | 0 128 | */ 129 | ``` 130 | 131 | 2) Factorial 132 | 133 | ```javascript 134 | const factorial = (num) => 135 | num <= 0 136 | ? 1 137 | : n * factorial(num - 1) 138 | 139 | factorial(5); 140 | //120 141 | ``` 142 | 143 | ### Functor 144 | An object that has a map method. The map method of the functor takes it’s own contents and transforms each of them using the transformation callback passed to map, and returns a new functor, which contains the structure as the first functor, but with the transformed values. 145 | 146 | 1) Adding a value to all the elements in a array 147 | 148 | ```javascript 149 | const plus1 = num => num + 1; 150 | 151 | let numbers = [1, 2, 3]; 152 | numbers.map(plus1); 153 | // [2, 3, 4] 154 | ``` 155 | 156 | ### Compose 157 | The composition of two or more functions returns a new function. 158 | 159 | 1) Combining two functions to generate another one 160 | 161 | ```javascript 162 | const compose = (f,g) => x => f(g(x)); 163 | 164 | const toUpperCase = x => x.toUpperCase(); 165 | const exclaim = x => `${x}!`; 166 | 167 | const angry = compose(exclaim, toUpperCase); 168 | 169 | angry("stop this"); 170 | // STOP THIS! 171 | ``` 172 | 173 | 2) Combining three functions to generate another one 174 | 175 | ```javascript 176 | const compose = (f,g) => x => f(g(x)); 177 | 178 | const toUpperCase = x => x.toUpperCase(); 179 | const exclaim = x => `${x}!`; 180 | const moreExclaim = x => `${x}!!!!!`; 181 | 182 | const reallyAngry = compose(exclaim, compose(toUpperCase, moreExclaim)); 183 | 184 | reallyAngry("stop this"); 185 | // STOP THIS!!!!!! 186 | ``` 187 | 188 | ### Destructuring 189 | Extract data from arrays or objects using a syntax that mirrors the construction of array and object literals. Or "Pattern Matching". 190 | 191 | 1) Select from pattern 192 | 193 | ```javascript 194 | const foo = () => [1, 2, 3]; 195 | 196 | const [a, b] = foo(); 197 | console.log(a, b); 198 | // 1 2 199 | ``` 200 | 201 | 2) Accumulates the rest values 202 | 203 | ```javascript 204 | const [a, ...b] = [1, 2, 3]; 205 | console.log(a, b); 206 | // 1 [2, 3] 207 | ``` 208 | 209 | 3) Optional parameters 210 | 211 | ```javascript 212 | const ajax = ({ url = "localhost", port: p = 80}, ...data) => 213 | console.log("Url:", url, "Port:", p, "Rest:", data); 214 | 215 | ajax({ url: "someHost" }, "additional", "data", "hello"); 216 | // Url: someHost Port: 80 Rest: [ 'additional', 'data', 'hello' ] 217 | 218 | ajax({ }, "additional", "data", "hello"); 219 | // Url: localhost Port: 80 Rest: [ 'additional', 'data', 'hello' ] 220 | ``` 221 | 222 | ### Currying 223 | Taking a function that takes multiple arguments and turning it into a chain of functions each taking one argument and returning the next function, until the last returns the result. 224 | 225 | 1) Currying an Object 226 | 227 | ```javascript 228 | const student = name => grade => `Name: ${name} | Grade: ${grade}`; 229 | 230 | student("Matt")(8); 231 | // Name: Matt | Grade: 8 232 | ``` 233 | 234 | 2) Currying a Sum 235 | 236 | ```javascript 237 | const add = x => y => x + y; 238 | 239 | const increment = add(1); 240 | const addFive = add(5); 241 | 242 | increment(3); 243 | //4 244 | 245 | addFive(10); 246 | // 15 247 | ``` 248 | 249 | ### Sources 250 | - [Gist: Usages for ES6 destructuring](https://gist.github.com/mikaelbr/9900818) 251 | 252 | - [Functional JavaScript Mini Book by Jichao Ouyang](https://jcouyang.gitbooks.io/functional-javascript/content/en/index.html) 253 | 254 | - [Functional Programming in JavaScript series by mpj](https://www.youtube.com/playlist?list=PL0zVEGEvSaeEd9hlmCXrk5yUyqUag-n84) 255 | 256 | - [Functors in Javascript](http://functionaljavascript.blogspot.com.br/2013/07/functors.html) 257 | 258 | - [Pure functions in Javascript](http://nicoespeon.com/en/2015/01/pure-functions-javascript/) 259 | 260 | - [Professor Frisby's Mostly Adequate Guide to Functional Programming](https://drboolean.gitbooks.io/mostly-adequate-guide/) 261 | 262 | - [Functors by mpj](https://www.youtube.com/watch?v=DisD9ftUyCk) 263 | 264 | - [Concepts of Functional Programming in Javascript](https://medium.com/the-renaissance-developer/concepts-of-functional-programming-in-javascript-6bc84220d2aa) 265 | -------------------------------------------------------------------------------- /examples.js: -------------------------------------------------------------------------------- 1 | // pure fuctions 2 | var number = 1; 3 | var increment = function() { 4 | return number += 1; 5 | }; 6 | console.log(increment()); 7 | 8 | var increment = function(n) { 9 | return n + 1; 10 | }; 11 | console.log(increment(1)); 12 | 13 | // Sum 14 | let sum = (x, y) => { 15 | return x + y; 16 | } 17 | 18 | let calculate = (fn, x, y) => { 19 | return fn(x, y); 20 | } 21 | 22 | let calc = calculate(sum, 1, 2); 23 | console.log(calc); // 3 24 | 25 | // Filter 26 | let students = [ 27 | {name: 'Anna', grade: 6}, 28 | {name: 'John', grade: 4}, 29 | {name: 'Maria', grade: 9} 30 | ]; 31 | 32 | let isApproved = (student) => { 33 | return student.grade >= 6; 34 | } 35 | 36 | let approvedStudents = students.filter(isApproved); 37 | console.log(approvedStudents); 38 | // [ { name: 'Anna', grade: 6 }, { name: 'Maria', grade: 9 } ] 39 | 40 | // Map 41 | let byName = (obj) => { 42 | return obj.name; 43 | } 44 | 45 | let studentsByName = students.map(byName); 46 | console.log(studentsByName); 47 | // [ 'Anna', 'John', 'Maria' ] 48 | 49 | // Chaining 50 | console.log(students.filter(isApproved).map(byName)); 51 | 52 | // Reduce 53 | let totalGrades = students.reduce((sum, student) => { 54 | return sum + student.grade; 55 | }, 0); 56 | console.log(totalGrades); 57 | 58 | // Currying 59 | let currySum = 60 | x => 61 | y => 62 | x + y; 63 | 64 | let incr = currySum(1); 65 | let addFive = currySum(5); 66 | let adding = incr(10); 67 | console.log(adding); // 15 68 | 69 | let student = 70 | name => 71 | grade => 72 | `Name: ${name} | Grade: ${grade}`; 73 | 74 | let myStudent = student("Matt")(8); 75 | console.log(myStudent); // Name: Matt | Grade: 8 76 | 77 | // Functor 78 | let plus1 = (num) => { 79 | return num + 1; 80 | } 81 | let numbers = [1, 2, 3]; 82 | console.log(numbers.map(plus1)); 83 | 84 | // compose 85 | 86 | let compose = function(f,g) { 87 | return function(x) { 88 | return f(g(x)); 89 | }; 90 | }; 91 | 92 | let toUpperCase = function(x) { return x.toUpperCase(); }; 93 | let exclaim = function(x) { return x + '!'; }; 94 | let angry = compose(exclaim, (toUpperCase)); 95 | 96 | console.log(angry("send in the clowns")); 97 | 98 | 99 | // Destructuring 100 | let foo = () => { 101 | return [1, 2, 3]; 102 | }; 103 | 104 | let [a, b] = foo(); 105 | console.log(a, b); // 1 2 106 | 107 | let [x, ...y] = [1, 2, 3]; 108 | console.log(x, y); // 1 [2, 3] 109 | 110 | let ajax = function ({ url = "localhost", port: p = 80}, ...data) { 111 | console.log("Url:", url, "Port:", p, "Rest:", data); 112 | }; 113 | 114 | ajax({ url: "someHost" }, "additional", "data", "hello"); 115 | // Url: someHost Port: 80 Rest: [ 'additional', 'data', 'hello' ] 116 | 117 | ajax({ }, "additional", "data", "hello"); 118 | // Url: localhost Port: 80 Rest: [ 'additional', 'data', 'hello' ] 119 | 120 | // Recursion 121 | let countdown = (num) => { 122 | console.log(num); 123 | num < 1 124 | ? num 125 | : countdown(num -1); 126 | } 127 | 128 | let counting = countdown(5); 129 | /* 130 | 5 131 | 4 132 | 3 133 | 2 134 | 1 135 | */ 136 | 137 | let factorial = (num) => 138 | num <= 0 139 | ? 1 140 | : n * factorial(num - 1); 141 | 142 | console.log(factorial(5)); 143 | //120 144 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "js-functional", 3 | "version": "1.0.0", 4 | "description": "JavaScript Functional Programming Cookbook (ES6)", 5 | "main": "examples.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "keywords": [ 10 | "Functional", 11 | "Cookbook", 12 | "JavaScript", 13 | "ES6" 14 | ], 15 | "author": "Matheus Lima", 16 | "license": "MIT", 17 | "devDependencies": { 18 | "babel": "^5.8.23" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /translations/pt-BR/README.md: -------------------------------------------------------------------------------- 1 | ## Livro de receitas - Programação Funcional em JavaScript (ES6) 2 | Um livro de receitas para escrever _programação funcional_ no JavaScript com ES6. 3 | 4 | ### Índice 5 | 6 | * [Funções puras](#funções-puras) 7 | * [O que são "Higher-order functions"](#o-que-são-higher-order-functions) 8 | * [Recursão](#recursão) 9 | * [O que são "Functors"](#o-que-são-functors) 10 | * [Compondo funções](#compondo-funções) 11 | * [Usando desestruturação de parâmetros](#usando-desestruturação-de-parâmetros) 12 | * [O que é "Currying"](#o-que-é-currying) 13 | 14 | ### Funções puras 15 | Retorna o mesmo valor se passado os mesmos parâmetros. Sua execução não depende do estado do sistema. 16 | 17 | 1) Função impura 18 | 19 | ```javascript 20 | let number = 1; 21 | 22 | const increment = () => number += 1; 23 | 24 | increment(); 25 | // 2 26 | ``` 27 | 28 | 2) Função pura 29 | 30 | ```javascript 31 | const increment = n => n + 1; 32 | 33 | increment(1); 34 | // 2 35 | ``` 36 | 37 | ### O que são "Higher-order functions" 38 | São funções que operam em outras funções, seja por receber elas como argumentos ou retornando-a como valor. 39 | 40 | 1) Função de soma 41 | 42 | ```javascript 43 | const sum = (x, y) => x + y; 44 | 45 | const calculate = (fn, x, y) => fn(x, y); 46 | 47 | calculate(sum, 1, 2); 48 | // 3 49 | ``` 50 | 51 | 2) Filtrando elementos 52 | 53 | ```javascript 54 | let students = [ 55 | {name: 'Anna', grade: 6}, 56 | {name: 'John', grade: 4}, 57 | {name: 'Maria', grade: 9} 58 | ]; 59 | 60 | const isApproved = student => student.grade >= 6; 61 | 62 | students.filter(isApproved); 63 | // [ { name: 'Anna', grade: 6 }, { name: 'Maria', grade: 9 } ] 64 | ``` 65 | 66 | 3) Map 67 | 68 | ```javascript 69 | const byName = obj => obj.name; 70 | 71 | students.map(byName); 72 | // [ 'Anna', 'John', 'Maria' ] 73 | ``` 74 | 75 | 4) Encadeando funções 76 | 77 | ```javascript 78 | let students = [ 79 | {name: 'Anna', grade: 6}, 80 | {name: 'John', grade: 4}, 81 | {name: 'Maria', grade: 9} 82 | ]; 83 | 84 | const isApproved = student => student.grade >= 6; 85 | 86 | const byName = obj => obj.name; 87 | 88 | students.filter(isApproved).map(byName); 89 | // ['Anna', 'Maria'] 90 | ``` 91 | 92 | 5) Usando _reduce_ 93 | 94 | ```javascript 95 | const totalGrades = students.reduce((sum, student) => sum + student.grade, 0); 96 | 97 | totalGrades 98 | // 19 99 | ``` 100 | 101 | ### Recursão 102 | Sempre que uma função chama a si mesmo, criando um loop. 103 | 104 | 1) Função de contagem regressiva 105 | 106 | ```javascript 107 | const countdown = num => { 108 | console.log(num) 109 | num < 1 110 | ? num 111 | : countdown(num - 1) 112 | } 113 | 114 | countdown(5); 115 | /* 116 | 5 117 | 4 118 | 3 119 | 2 120 | 1 121 | 0 122 | */ 123 | ``` 124 | 125 | 2) Calculando uma fatorial 126 | 127 | ```javascript 128 | const factorial = (num) => 129 | num <= 0 130 | ? 1 131 | : n * factorial(num - 1) 132 | 133 | factorial(5); 134 | //120 135 | ``` 136 | 137 | ### O que são "Functors" 138 | É um objeto que implementa o método _map_. O método _map_ do _functor_ retorna seu próprio conteúdo e, para cada um deles, processa a transformação passada como _callback_ para o método _map_ e retorna um novo _functor_, que contém a estrutura do primeiro _functor_, porém, com seu conteúdo transformado. 139 | 140 | 1) Adicionando um valor a todos os elementos em um array 141 | 142 | ```javascript 143 | const plus1 = num => num + 1; 144 | 145 | let numbers = [1, 2, 3]; 146 | numbers.map(plus1); 147 | // [2, 3, 4] 148 | ``` 149 | 150 | ### Compondo funções 151 | A composição de duas ou mais funções retornando uma nova função. 152 | 153 | 1) Combinando duas funções para gerar uma nova 154 | 155 | ```javascript 156 | const compose = (f,g) => x => f(g(x)); 157 | 158 | const toUpperCase = x => x.toUpperCase(); 159 | const exclaim = x => `${x}!`; 160 | 161 | const angry = compose(exclaim, toUpperCase); 162 | 163 | angry("stop this"); 164 | // STOP THIS! 165 | ``` 166 | 167 | 2) Combinando três funções para gerar uma nova 168 | 169 | ```javascript 170 | const compose = (f,g) => x => f(g(x)); 171 | 172 | const toUpperCase = x => x.toUpperCase(); 173 | const exclaim = x => `${x}!`; 174 | const moreExclaim = x => `${x}!!!!!`; 175 | 176 | const reallyAngry = compose(exclaim, compose(toUpperCase, moreExclaim)); 177 | 178 | reallyAngry("stop this"); 179 | // STOP THIS!!!!!! 180 | ``` 181 | 182 | ### Usando desestruturação de parâmetros 183 | Extrair dados de arrays ou objetos usando uma sintaxe que espelha a estrutura literal do array ou objeto. Conhecida também como _"Pattern Matching"_ (em português, algo como, **correspondendo ao mesmo padrão**). 184 | 185 | 1) Selecionando a partir de um padrão 186 | 187 | ```javascript 188 | const foo = () => [1, 2, 3]; 189 | 190 | const [a, b] = foo(); 191 | console.log(a, b); 192 | // 1 2 193 | ``` 194 | 195 | 2) Acumula os valores de restantes 196 | 197 | ```javascript 198 | const [a, ...b] = [1, 2, 3]; 199 | console.log(a, b); 200 | // 1 [2, 3] 201 | ``` 202 | 203 | 3) Parâmetros opcionais 204 | 205 | ```javascript 206 | const ajax = ({ url = "localhost", port: p = 80}, ...data) => 207 | console.log("Url:", url, "Port:", p, "Rest:", data); 208 | 209 | ajax({ url: "someHost" }, "additional", "data", "hello"); 210 | // Url: someHost Port: 80 Rest: [ 'additional', 'data', 'hello' ] 211 | 212 | ajax({ }, "additional", "data", "hello"); 213 | // Url: localhost Port: 80 Rest: [ 'additional', 'data', 'hello' ] 214 | ``` 215 | 216 | ### O que é "Currying" 217 | Recebe uma função que recebe múltiplos argumentos e transforma isso em um encadeamento de funções, passando um argumento de cada vez e retornando a próxima função, até que a última retorne o resultado. 218 | 219 | 1) Utilizando _currying_ em um objeto 220 | 221 | ```javascript 222 | const student = name => grade => `Name: ${name} | Grade: ${grade}`; 223 | 224 | student("Matt")(8); 225 | // Name: Matt | Grade: 8 226 | ``` 227 | 228 | 2) Utilizando _currying_ em uma função de soma 229 | 230 | ```javascript 231 | const add = x => y => x + y; 232 | 233 | const increment = add(1); 234 | const addFive = add(5); 235 | 236 | increment(3); 237 | //4 238 | 239 | addFive(10); 240 | // 15 241 | ``` 242 | 243 | ### Artigos relacionados 244 | 245 | **OBS:** Todos em inglês. 246 | 247 | [https://gist.github.com/mikaelbr/9900818](https://gist.github.com/mikaelbr/9900818) 248 | 249 | [https://www.gitbook.com/book/jcouyang/functional-javascript/details](https://www.gitbook.com/book/jcouyang/functional-javascript/details) 250 | 251 | [https://www.youtube.com/playlist?list=PL0zVEGEvSaeEd9hlmCXrk5yUyqUag-n84](https://www.youtube.com/playlist?list=PL0zVEGEvSaeEd9hlmCXrk5yUyqUag-n84) 252 | 253 | [http://functionaljavascript.blogspot.com.br/2013/07/functors.html](http://functionaljavascript.blogspot.com.br/2013/07/functors.html) 254 | 255 | [http://nicoespeon.com/en/2015/01/pure-functions-javascript/](http://nicoespeon.com/en/2015/01/pure-functions-javascript/) 256 | 257 | [https://drboolean.gitbooks.io/mostly-adequate-guide/](https://drboolean.gitbooks.io/mostly-adequate-guide/) 258 | 259 | [https://www.youtube.com/watch?v=DisD9ftUyCk](https://www.youtube.com/watch?v=DisD9ftUyCk) 260 | -------------------------------------------------------------------------------- /translations/zh-CN/README.md: -------------------------------------------------------------------------------- 1 | ## JavaScript 函数式编程手册 (ES6) 2 | 一份用 ES6 写的 JavaScript 函数式编程手册 3 | 4 | **Translations** 5 | 6 | - [Português (Brasil)](/translations/pt-BR/README.md) 7 | - [简体中文版](/translations/zh-CN/README.md) 8 | 9 | ### 概要 10 | 11 | * [Pure functions](#纯函数式) 12 | * [Higher-order functions](#高阶函数) 13 | * [Recursion](#递归) 14 | * [Functor](#functor) 15 | * [Compose](#组合) 16 | * [Destructuring](#解构) 17 | * [Currying](#柯里化) 18 | 19 | ### 纯函数式 20 | 21 | 相同的参数返回相同的结果,它的执行不依赖于系统的状态 22 | 23 | 1) 非纯净的 24 | 25 | ```javascript 26 | let number = 1; 27 | 28 | const increment = () => number += 1; 29 | 30 | increment(); 31 | // 2 32 | ``` 33 | 34 | 2) 纯净的 35 | 36 | ```javascript 37 | const increment = n => n + 1; 38 | 39 | increment(1); 40 | // 2 41 | ``` 42 | 43 | ### 高阶函数 44 | 函数把其他函数当做参数传递使用或者返回一个函数 45 | 1) 加法 46 | 47 | ```javascript 48 | const sum = (x, y) => x + y; 49 | 50 | const calculate = (fn, x, y) => fn(x, y); 51 | 52 | calculate(sum, 1, 2); 53 | // 3 54 | ``` 55 | 56 | 2) filter 57 | 58 | ```javascript 59 | let students = [ 60 | {name: 'Anna', grade: 6}, 61 | {name: 'John', grade: 4}, 62 | {name: 'Maria', grade: 9} 63 | ]; 64 | 65 | const isApproved = student => student.grade >= 6; 66 | 67 | students.filter(isApproved); 68 | // [ { name: 'Anna', grade: 6 }, { name: 'Maria', grade: 9 } ] 69 | ``` 70 | 71 | 3) Map 72 | 73 | ```javascript 74 | const byName = obj => obj.name; 75 | 76 | students.map(byName); 77 | // [ 'Anna', 'John', 'Maria' ] 78 | ``` 79 | 80 | 4) 链式 81 | 82 | ```javascript 83 | let students = [ 84 | {name: 'Anna', grade: 6}, 85 | {name: 'John', grade: 4}, 86 | {name: 'Maria', grade: 9} 87 | ]; 88 | 89 | const isApproved = student => student.grade >= 6; 90 | 91 | const byName = obj => obj.name; 92 | 93 | students.filter(isApproved).map(byName); 94 | // ['Anna', 'Maria'] 95 | ``` 96 | 97 | 5) Reduce 98 | 99 | ```javascript 100 | const totalGrades = students.reduce((sum, student) => sum + student.grade, 0); 101 | 102 | totalGrades 103 | // 19 104 | ``` 105 | 106 | ### 递归 107 | 108 | 当一个函数调用它自己的时候,就创造了一个循环 109 | 110 | 1) 递减 111 | 112 | ```javascript 113 | const countdown = num => { 114 | console.log(num) 115 | num < 1 116 | ? num 117 | : countdown(num - 1) 118 | } 119 | 120 | countdown(5); 121 | /* 122 | 5 123 | 4 124 | 3 125 | 2 126 | 1 127 | 0 128 | */ 129 | ``` 130 | 131 | 2) 阶乘 132 | 133 | ```javascript 134 | const factorial = (num) => 135 | num <= 0 136 | ? 1 137 | : n * factorial(num - 1) 138 | 139 | factorial(5); 140 | //120 141 | ``` 142 | 143 | ### Functor 144 | 有 map 方法的对象。functor 的 map 方法通过 map 回调函数调用自己的内容,然后返回一个新的 functor. 145 | 146 | 1) 给数组所有的元素添加一个值 147 | 148 | ```javascript 149 | const plus1 = num => num + 1; 150 | 151 | let numbers = [1, 2, 3]; 152 | numbers.map(plus1); 153 | // [2, 3, 4] 154 | ``` 155 | 156 | ### 组合 157 | 158 | 通过组合两个或更多的函数生成一个新的函数 159 | 160 | 1) 组合两个函数生成一个新的函数 161 | 162 | ```javascript 163 | const compose = (f,g) => x => f(g(x)); 164 | 165 | const toUpperCase = x => x.toUpperCase(); 166 | const exclaim = x => `${x}!`; 167 | 168 | const angry = compose(exclaim, toUpperCase); 169 | 170 | angry("stop this"); 171 | // STOP THIS! 172 | ``` 173 | 174 | 2) 组合三个函数生成一个新的 175 | 176 | ```javascript 177 | const compose = (f,g) => x => f(g(x)); 178 | 179 | const toUpperCase = x => x.toUpperCase(); 180 | const exclaim = x => `${x}!`; 181 | const moreExclaim = x => `${x}!!!!!`; 182 | 183 | const reallyAngry = compose(exclaim, compose(toUpperCase, moreExclaim)); 184 | 185 | reallyAngry("stop this"); 186 | // STOP THIS!!!!!! 187 | ``` 188 | 189 | ### 解构 190 | 191 | 从数组中提取数据或对象使用一种语法混合数组和对象文本的建设。或“模式匹配”。 192 | 193 | 1) Select from pattern 194 | 195 | ```javascript 196 | const foo = () => [1, 2, 3]; 197 | 198 | const [a, b] = foo(); 199 | console.log(a, b); 200 | // 1 2 201 | ``` 202 | 203 | 2) 接收 rest 值 204 | 205 | ```javascript 206 | const [a, ...b] = [1, 2, 3]; 207 | console.log(a, b); 208 | // 1 [2, 3] 209 | ``` 210 | 211 | 3) 可选参数 212 | 213 | ```javascript 214 | const ajax = ({ url = "localhost", port: p = 80}, ...data) => 215 | console.log("Url:", url, "Port:", p, "Rest:", data); 216 | 217 | ajax({ url: "someHost" }, "additional", "data", "hello"); 218 | // Url: someHost Port: 80 Rest: [ 'additional', 'data', 'hello' ] 219 | 220 | ajax({ }, "additional", "data", "hello"); 221 | // Url: localhost Port: 80 Rest: [ 'additional', 'data', 'hello' ] 222 | ``` 223 | 224 | ### 柯里化 225 | 226 | 一个函数有多个参数,把每个参数通过链式的形式返回下一个函数,直到最后返回结果。 227 | 228 | 229 | 1) 对象柯里化 230 | 231 | ```javascript 232 | const student = name => grade => `Name: ${name} | Grade: ${grade}`; 233 | 234 | student("Matt")(8); 235 | // Name: Matt | Grade: 8 236 | ``` 237 | 238 | 2) 加法函数柯里化 239 | 240 | ```javascript 241 | const add = x => y => x + y; 242 | 243 | const increment = add(1); 244 | const addFive = add(5); 245 | 246 | increment(3); 247 | //4 248 | 249 | addFive(10); 250 | // 15 251 | ``` 252 | 253 | ### 参考资源 254 | [https://gist.github.com/mikaelbr/9900818](https://gist.github.com/mikaelbr/9900818) 255 | 256 | [https://www.gitbook.com/book/jcouyang/functional-javascript/details](https://www.gitbook.com/book/jcouyang/functional-javascript/details) 257 | 258 | [https://www.youtube.com/playlist?list=PL0zVEGEvSaeEd9hlmCXrk5yUyqUag-n84](https://www.youtube.com/playlist?list=PL0zVEGEvSaeEd9hlmCXrk5yUyqUag-n84) 259 | 260 | [http://functionaljavascript.blogspot.com.br/2013/07/functors.html](http://functionaljavascript.blogspot.com.br/2013/07/functors.html) 261 | 262 | [http://nicoespeon.com/en/2015/01/pure-functions-javascript/](http://nicoespeon.com/en/2015/01/pure-functions-javascript/) 263 | 264 | [https://drboolean.gitbooks.io/mostly-adequate-guide/](https://drboolean.gitbooks.io/mostly-adequate-guide/) 265 | 266 | [https://www.youtube.com/watch?v=DisD9ftUyCk](https://www.youtube.com/watch?v=DisD9ftUyCk) 267 | --------------------------------------------------------------------------------