Function composition là ghép nhiều hàm nhỏ thành một hàm lớn, đầu ra của hàm này là đầu vào của hàm kế tiếp.
javascript
const compose = (...fns) => (x) => fns.reduceRight((v, f) => f(v), x)
const pipe = (...fns) => (x) => fns.reduce((v, f) => f(v), x)Hai cái chỉ khác chiều đọc:
javascript
const trim = (s) => s.trim()
const lower = (s) => s.toLowerCase()
const slugify = (s) => s.replace(/\s+/g, '-')
compose(slugify, lower, trim)(' Học React ') // đọc từ PHẢI sang trái
pipe(trim, lower, slugify)(' Học React ') // đọc từ TRÁI sang phải — dễ hơn
// → 'học-react'Lợi ích so với biến trung gian:
javascript
// không compose
const a = trim(input)
const b = lower(a)
const c = slugify(b)
// compose: đặt tên cho cả pipeline, tái dùng được
const toSlug = pipe(trim, lower, slugify)
titles.map(toSlug)Gặp ở đâu trong thực tế: applyMiddleware của Redux, chuỗi transform của RxJS, plugin của PostCSS/Babel.
Lưu ý 1: mỗi hàm trong chuỗi phải nhận đúng một tham số. Hàm nhiều tham số phải curry trước.
Lưu ý 2: compose chỉ chạy đồng bộ. Có bước bất đồng bộ thì cần bản riêng:
javascript
const pipeAsync = (...fns) => (x) => fns.reduce((p, f) => p.then(f), Promise.resolve(x))