Funtional programming là kiểu xử lý các tính toán như đánh giá của các hàm toán học, tránh thay đổi state và dữ liệu mutable
Arrow function
Arrow function (Hàm dùng ký hiệu =>) giúp tạo các expression ngắn gọn, đóng gói một phần nhỏ chức năng. Ngoài ra, các arrow giữ phạm vi của phía gọi bên trong hàm loại bỏ nhu cầu self = this.
Ví dụ
const multiply = function(x,y) { return x * y; } // Có thể viết lại như sau const multiply = (x, y) => { return x * y }; // Do hàm trả về mộ expression đơn nên không cần dấu đóng const multiply = (x, y) => x * y; console.log(multiply(5,10)) //50
Function Delegate
Function Delegate đóng gói một phương thức cho phép các hàm được tạo hoặc được truyền dưới dạng dữ liệu
Ví dụ
const isZero = n => n === 0; const a = [0,1,0,3,4,0]; console.log(a.filter(isZero).length); // 3
Expression thay cho Statement
Các Statement định nghĩa một hành vi và được thực thi với side effect (tác nhân bên ngoài). Expression tạo ra kết quả với state không thay đổi ( no side effect)
Statement
const getSalutation = function(hour) { var salutation; // Giá trị temp if (hour < 12) { salutation = "Good Morning"; } else { salutation = "Good Afternoon" } return salutation; // Gía trị mutable }
Expression
const getSalutation = (hour) => hour < 12 ? "Good Morning" : "Good Afternoon"; console.log(getSalutation(10)); // Good Morning
Higher order function
Một hàm nhận hàm khác như một tham số hoặc trả về một hàm khác
Ví dụ
function mapConsecutive(values, fn) { let result = []; for(let i=0; i < values.length -1; i++) { result.push(fn(values[i], values[i+1])); } return result; } const letters = ['a','b','c','d','e','f','g']; let twoByTwo = mapConsecutive(letters, (x,y) => [x,y]); console.log(twoByTwo); // [[a,b], [b,c], [c,d], [d,e], [e,f], [f,g]]
Currying
Currying cho phép một hàm có nhiều tham số được dịch sang thành một chuỗi các hàm. Hàm Currying có thể được điều chỉnh để phù hợp với chữ ký của hàm khác
Ví dụ
const convertUnits = (toUnit, factor, offset = 0) => input => ((offset + input) * factor).toFixed(2).concat(toUnit); const milesToKm = convertUnits('km', 1.60936, 0); const poundsToKg = convertUnits('kg', 0.45460, 0); const farenheitToCelsius = convertUnits('degrees C', 0.5556, -32); milesToKm(10); //"16.09 km" poundsToKg(2.5); //"1.14 kg" farenheitToCelsius(98); //"36.67 degrees C" const weightsInPounds = [5,15.4,9.8, 110]; // Không dùng currying const weightsInKg = weightsInPounds.map(x => convertUnits('kg', 0.45460, 0)(x)); // dùng currying const weightsInKg = weightsInPounds.map(poundsToKg); // 2.27kg, 7.00kg, 4.46kg, 50.01kg
Các hàm tương tác với mảng
Các hàm mảng là cửa ngõ đến Functional programming trong Javascript. Các hàm này giúp các công việc xử lý ngắn gọn của hầu hết thói quen lập trình quen thuộc hoạt động trên mảng hoặc collection
[].every(fn)
Kiểm tra tất cả các phần tử trong mảng thoả mãn điều kiện test[].some(fn) | [].includes(fn)
Kiểm tra phần tử bất kỳ trong mảng thoả mãn điều kiện test[].find(fn)
Trả về phần tử đầu tiên trong mảng thoả mãn điều kiện test[].filter(fn)
trả về tất cả các phần tử trong mảng thoả mãn điều kiện test[].map(fn)
Trả về một mảng mới là kết qủa khi gọi một hàm nhận tất cả các phần tử của mảng như tham số đầu vào[].reduce(fn(accumulator, currentValue))
Thực hiện một hàm được cung cấp cho mỗi phần tử của mảng (từ trái sang phải), trả về một giá trị duy nhất, accumulator[].sort(fn(a,b))
– sử dụng mutable state, chỉnh sửa một mảng bằng cách sắp xếp các phần tử trong mảng. Một lựa chọn khác là sử dụng hàm so sánh để chỉnh sửa điều kiện sắp xếp[...arr].sort()
Dùng cách naỳ để sắp xếp tránh không dùng mutable[].reverse()
mutable state, đảo ngược thứ tự các phần tử trong mảng-
[...arr].reverse()
đảo ngược thứ tự tránh không dùng mutable
Xâu chuỗi các phương thức
Xâu chuỗi các phương thức để cho phép một chuỗi các hàm gọi liên tiếp nhau mục đích để đạt được kết quả cuối cùng. Xâu chuỗi các phương thức cho phép thành phần hàm giống như một đường ống
Ví dụ
let cart = [ {name: "Drink", price: 3.12}, {name: "Steak", price: 45.15}, {name: "Drink", price: 11.01} ]; let drinkTotal = cart.filter(x=> x.name === "Drink") .map(x=> x.price) .reduce((t,v) => t +=v) .toFixed(2); console.log(Total Drink Cost $${drinkTotal}); // Total Drink Cost $14.13
Pipelines
Một Pipeline cho phép thành phần hàm dễ dàng khi thực hiện nhiều hoạt động khác nhau trên một biến. Vì Javascript thiếu một toán tử Pipeline, một design pattern có thể được sử dụng hoàn thành task
Ví dụ
const pipe = functions => data => { return functions.reduce( (value, func) => func(value), data); }; let cart = [3.12, 45.15, 11.01]; const addSalesTax = (total, taxRate) => (total * taxRate) + total; const tally = orders => pipe([ x => x.reduce((total, val) => total + val), // tính tổng các order x => addSalesTax(x, 0.09), x => `Order Total = ${x.toFixed(2)}` // chuyển đổi thành text ])(orders); // Order Total = 64.62