高阶函数及 map、reduce、filter 的实现
- 2020 年 2 月 14 日
- 筆記
函数
函数是函数式编程的工作单元与中心。函数是任何可调用你且可通过 () 操作求值的表达式。
JavaScript 函数有两个支柱性的重要特性:一等函数和高阶函数
一等函数就是最常见的,如:
function multiplier(a, b) { return a * b } let square = function(x) { return x * x } // lambda 表达式(箭头函数) let square = x => x * x
主要说说高阶函数
高阶函数
鉴于函数的行为与普通对象类似,其理所当然地可以作为其他函数的参数进行传递,或是由其他函数返回。这些函数则称为高阶函数。~JavaScript函数式编程指南p36~
例如 Array.sort 的 comparator 函数就是高阶函数(传送门:https://ainyi.com/41 -> sort 函数)
function add(a) { return function(b) { return a + b } } add(1)(2)
上面例子,add 函数接收一个参数,并返回另一个接收第二个参数并把它们加在一起的函数
函数柯里化能够很好地体现高阶函数的应用
function currying(fn, length) { length = length || fn.length; return function (...args) { return args.length >= length ? fn.apply(this, args) : currying(fn.bind(this, ...args), length - args.length) } } const add = currying(function(a, b, c) { console.log([a, b, c].reduce((a, b) => a + b)) }) add(1, 2, 3) // 6 add(1, 2)(3) // 6 add(1)(2)(3) // 6 add(1)(2, 3) // 6
兼容各种 add 调用的高阶函数
详情看我之前写的文章 js 高阶函数之柯里化
map、reduce、filter
此三种函数均为高阶函数,如何实现这三个函数,接下来看看。
一般重写对象的实例方法是通过 prototype,数组的所有实例方法、属性都保存在 Array.prototype。只不过平常都是通过该对象的实例调用
通过 _.实例方法,该实例方法的 this 指针指向它
map 的实现
高阶函数 map 能够将一个迭代函数有序地应用于一个数组中的每个元素,并返回一个长度相等的新数组
function map(fn) { let idx = -1, len = this.length, result = new Array(len) while (++idx < len) { result[idx] = fn(this[idx], idx, this) } console.log('myself') return result } Array.prototype.map = map; [1, 2, 3].map(ele => `#${ele}#`) // myself // ["#1#", "#2#", "#3#"]
reduce 实现
高阶函数 reduce 将一个数组中的元素精简为单一的值,该值是由每个元素与一个累计值通过一个函数计算得出的
function reduce(fn, accumulator) { let idx = -1, len = this.length if (!accumulator && len > 0) { accumulator = this[++idx] } while (++idx < len) { accumulator = fn(accumulator, this[idx], idx, this) } console.log('myself') return accumulator } Array.prototype.reduce = reduce; [1, 2, 3].reduce((n, p) => n + p) // myself // 6 // 也可以指定第一个累计值 [1, 2, 3].reduce((n, p) => n + p, 100) // myself // 106
filter 的实现
高阶函数 filter 能够遍历数组中的元素并过滤后返回一个新子集数组
function filter(fn) { let idx = -1, len = this.length result = [] while (++idx < len) { let value = this[idx] if (fn(value, idx, this)) { result.push(value) } } console.log('myself') return result } Array.prototype.filter = filter; [1, 2, 3].filter(ele => ele >= 2) // myself // [2, 3]