JS高阶函数与函数柯里化
高阶函数
满足下列条件之一的函数:
函数作为参数被传递(如回调函数);
函数可以作为返回值输出;
一些内置高阶函数的例子:
Array.prototype.map
map()方法通过调用对输入数组中的每个元素调用回调函数来创建一个新数组。
map()方法将获取回调函数的每个返回值,并使用这些值创建一个新数组。
map()方法的回调函数总共接收3个参数:element,index和array。
例子:
假设我们有一个数字数组,我们想创建一个新数组,新数组的每个值是原数组对应值的两倍。
不使用高阶函数:
const arr1 = [1, 2, 3];
const arr2 = [];
for(let i = 0; i < arr1.length; i ++) {
arr2.push(arr[i] * 2);
} console.log(arr2); //[2, 4, 6]
使用高阶函数:
const arr1 = [1, 2, 3];
const arr2 = arr1.map(item=> item * 2);
console.log(arr2);
Array.prototype.filter
filter()方法会创建一个新数组,其中包含所有通过回调函数测试的元素。传递给filter()方法的回调函数接受3个参数:element,index和array
例子:
假设我们有一个包含数字值的数组,选择其中的数值创建一个数值大于18的数组
不使用高阶函数:
const arr1 = [1, 2, 19, 20];
const arr2 = [];
for(let i = 0; i < arr1.length; i ++) {
if(arr1[i] > 18) {
arr2.push(arr1[1])
}
} console.log(arr2)
使用高阶函数:
const arr1 = [1, 2, 19, 20];
const arr2 = arr1.filter(item=> item > 18); console.log(arr2)
Array.prototype.reduce
reduce()方法对调用数组的每个元素执行回调函数,最后生成一个单一的值并返回。
reduce()方法接受两个参数:redecer函数(回调),一个可选的initialValue
reducer函数(回调)接受4个参数:accumulater, currentValue, currentIndex, sourceArray
如果提供了 initialValue,则累加器将等于 initialValue,currentValue 将等于数组中的第一个元素。
如果没有提供 initialValue,则累加器将等于数组中的第一个元素,currentValue 将等于数组中的第二个元素。
例子:
对一个数字数组的求和:
不使用高阶函数:
const arr = [1, 2, 7];
let sum = 0;
for(let i = 0; i< arr.length; i++) {
sum = sum + arr[i]
}
// 10
使用高阶函数:
const arr = [1, 2, 7];
const sum = arr.reduce((accumulator,currentValue)=>
return accumulator + currentValue )
//
还可以为它提供初始值:
const arr = [1, 2, 7];
const sum = arr.reduce((accumulator,currentValue)=>
return accumulator + currentValue,10 )
//
柯里化
柯里化(currying)又称部分求值。一个currying的函数首先会接受一些参数,接受这些参数之后,函数并不会立即求值,而是继续返回另一个函数,刚才传入的参数在函数形成的闭包中被保存起来。待到函数被真正需要求值的时候,之前传入的所有参数都会被一次性用于求值。
计算每天的花销
var currying = function(fn) { var args = []; return function() {
if (arguments.length === 0) {
return fn.apply(this, args);
} else {
Array.prototype.push.apply(args, arguments);
return arguments.callee;
}
}
} cost = function(){
var sum = 0;
for (var i = 0, len = arguments.length; i < len; i++) {
sum += arguments[i];
} return sum;
}
var cost = currying(cost); cost(100);
cost(200);
alert(cost())
通俗地讲,柯里化就是一个部分配置多参数函数的过程,每一步都返回一个接受单个参数的部分配置好的函数。一些极端的情况可能需要分很多次来部分配置一个函数,比如说多次相加:
multiPlus(1)(2)(3); // => 6
上代码
// ES5
function curry(fn) {
function _c(restNum, argsList) {
return restNum === 0 ?
fn.apply(null, argsList) :
function(x) {
return _c(restNum - 1, argsList.concat(x));
};
}
return _c(fn.length, []);
} // ES6
const curry = fn => {
const _c = (restNum, argsList) => restNum === 0 ?
fn(...argsList) : x => _c(restNum - 1, [...argsList, x]); return _c(fn.length, []);
} /***************** 使用 *********************/ var plus = curry(function(a, b) {
return a + b;
});
分析:
我们需要一个curry函数,它接受一个待柯里化的函数为参会素,返回一个用于接收一个参数的函数,接收到的参数放到一个列表中,当参数数量足够时,执行原函数并返回结果。
实现方式:
简单思考可以知道,柯里化部分配置函数的步骤数等于 fn 的参数个数,也就是说有两个参数的 plus 函数需要分两步来部分配置。函数的参数个数可以通过fn.length
获取。
总的想法就是每传一次参,就把该参数放入一个参数列表 argsList 中,如果已经没有要传的参数了,那么就调用fn.apply(null, argsList)
将原函数执行。要实现这点,我们就需要一个内部的判断函数 _c(restNum, argsList),函数接受两个参数,一个是剩余参数个数 restNum,另一个是已获取的参数的列表 argsList;_c 的功能就是判断是否还有未传入的参数,当 restNum 为零时,就是时候通过fn.apply(null, argsList)
执行原函数并返回结果了。如果还有参数需要传递的话,也就是说 restNum 不为零时,就需要返回一个单参数函数
function(x) {
return _c(restNum - 1, argsList.concat(x));
}
来继续接收参数。这里形成了一个尾递归,函数接受了一个参数后,剩余需要参数数量 restNum 减一,并将新参数 x 加入 argsList 后传入 _c 进行递归调用。结果就是,当参数数量不足时,返回负责接收新参数的单参数函数,当参数够了时,就调用原函数并返回。
现在再来看:
function curry(fn) {
function _c(restNum, argsList) {
return restNum === 0 ?
fn.apply(null, argsList) :
function(x) {
return _c(restNum - 1, argsList.concat(x));
};
}
return _c(fn.length, []); // 递归开始
}
可以使用ES6写法,用数组结构和箭头函数:
// ES6
const curry = fn => {
const _c = (restNum, argsList) => restNum === 0 ?
fn(...argsList) : x => _c(restNum - 1, [...argsList, x]); return _c(fn.length, []);
}
另外一种方法:
function curry(fn) {
const len = fn.length;
return function judge(...args1) {
return args1.length >= len ?
fn(...args1):
function(...args2) {
return judge(...[...args1, ...args2]);
}
}
} // 使用箭头函数
const curry = fn => {
const len = fn.length;
const judge = (...args1) => args1.length >= len ?
fn(...args1) : (...args2) => judge(...[...args1, ...args2]);
return judge;
}
JS高阶函数与函数柯里化的更多相关文章
- Java函数式编程:二、高阶函数,闭包,函数组合以及柯里化
承接上文:Java函数式编程:一.函数式接口,lambda表达式和方法引用 这次来聊聊函数式编程中其他的几个比较重要的概念和技术,从而使得我们能更深刻的掌握Java中的函数式编程. 本篇博客主要聊聊以 ...
- 浅析 JavaScript 中的 函数 uncurrying 反柯里化
柯里化 柯里化又称部分求值,其含义是给函数分步传递参数,每次传递参数后部分应用参数,并返回一个更具体的函数接受剩下的参数,这中间可嵌套多层这样的接受部分参数函数,直至返回最后结果. 因此柯里化的过程是 ...
- JS的防抖,节流,柯里化和反柯里化
今天我们来搞一搞节流,防抖,柯里化和反柯里化吧,是不是一看这词就觉得哎哟wc,有点高大上啊.事实上,我们可以在不经意间用过他们但是你却不知道他们叫什么,没关系,相信看了今天的文章你会有一些收获的 节流 ...
- JS高阶---变量与函数提升
大纲: 主体: 案例1: 接下来在控制台source里进行断点测试 打好断点后,在控制台测试window .
- JS的闭包、高阶函数、柯里化
本文原链接:https://cloud.tencent.com/developer/article/1326958 https://cloud.tencent.com/developer/articl ...
- js高阶函数应用—函数柯里化和反柯里化(二)
第上一篇文章中我们介绍了函数柯里化,顺带提到了偏函数,接下来我们继续话题,进入今天的主题-函数的反柯里化. 在上一篇文章中柯里化函数你可能需要去敲许多代码,理解很多代码逻辑,不过这一节我们讨论的反科里 ...
- Python高阶函数及函数柯里化
1 Python高阶函数 接收函数为参数,或者把函数作为结果返回的函数为高阶函数. 1.1 自定义sort函数 要求:仿照内建函数sorted,自行实现一个sort函数.内建函数sorted函数是返回 ...
- 从 ES6 高阶箭头函数理解函数柯里化
前言:第一次看到多个连续箭头函数是在一个 react 项目中,然鹅确认了下眼神,并不是对的人,因为看得一脸懵逼.em......于是开始各种搜索,先是知道了多个连续箭头函数就是 es6 的多次柯里化的 ...
- JS 函数的柯里化与反柯里化
===================================== 函数的柯里化与反柯里化 ===================================== [这是一篇比较久之前的总 ...
- 浅析 JavaScript 中的 函数 currying 柯里化
原文:浅析 JavaScript 中的 函数 currying 柯里化 何为Curry化/柯里化? curry化来源与数学家 Haskell Curry的名字 (编程语言 Haskell也是以他的名字 ...
随机推荐
- fabric 自动创建仓库并下载或更新代码
#!/usr/bin/python # -*- coding: utf-8 -* from fabric.api import * from fabric.contrib.files import * ...
- js中的encodeURIComponent()函数
encodeURIComponent() 函数可把字符串作为 URI 组件进行编码. $scope.linktotheme = function () { if ($scope.curthemeid ...
- SpringSecurity 3.2入门(5)自定义登录页面
增加spring-security.xml文件配置如下 <!-- 配置SpringSecurity的http安全服务 --> <security:http auto-config=& ...
- java版两人聊天程序
server.java import java.io.*; import java.net.*; import java.text.SimpleDateFormat; import java.util ...
- .net编程知识点
一.编程思想 OOP(面向对象) 面向对象三大特性(多态如何体现)及五项原则 AOP(面向切面编程) 面向切面编程静态植入和动态植入 二.c#23种设计模式 三.Castle是针对.NET平台的一个开 ...
- Web程序中使用EasyUI时乱码问题
今天偶然遇见使用easyUI时,弹窗和分页都是乱码的问题,耗费了很长的时间来解决,以此记住这个坑. 相信大家都会在使用easyUI时都会设置这样一句: 那么就有可能出现设置中文后的乱码问题,如下图: ...
- mysql 乱码问题的捣鼓
mysql在ubuntu的终端下出现中文乱码的问题: 先学着在不改数据库的情况下对my.cnf配置文件进行修改, 主要的是设置 default-character-set=utf8 但是设置完后数据库 ...
- 转:SQL Server附加数据库提示“版本为661,无法打开,支持655版本……”
在我们使用别人导出的数据库的时候,有时候我们会通过附加数据库的方法,把别人导出的数据库附加到我们的电脑中,这时,或许你会遇到这种问题,附加时,提示版本为XXX,无法打开,支持AAA版本. 这是怎么回事 ...
- .NET开源工作流RoadFlow-表单设计-数据表格
数据表格即在表单中显示一个table,该table数据可以来自任意自定义的来源: 数据类型:指定表格的数据源类型 1.datatable,即.net中的System.Data.DataTable 2. ...
- 有关在新版mac上 git 环境变量的配置问题
前段时间买的新版 mpb ,各种环境什么都没有配置,想着在网上边搜边摸索着将各种开发工具逐步配置齐全,各种问题不断出现,不知道是不是新版的原因不兼容. 其中 git 的配置尤为奇怪.在git官网上直接 ...