Javascript:是你的高阶函数
在通常的编程语言中,函数的参数只能是基本类型或者对象引用,返回值也只是基本数据类型或对象引用。但在Javascript中函数作为一等公民,既可以当做参数传递,也可以被当做返回值返回。所谓高阶函数就是可以把函数作为参数,或者是将函数作为返回值的函数。这两种情形在实际开发中有很多应用场景,本文是我在工作学习中遇到的几种应用场景的总结。
回调函数
代码复用是衡量一个应用程序的重要标准之一。通过将变化的业务逻辑抽离封装在回调函数中能够有效的提高代码复用率。比如ES5中为数组增加的forEach方法,遍历数组,对每个元素调用同一个函数。
array = {};
array.forEach = function(arr, fn){
for (var i = 0, len = arr.length; i < len; i++) {
fn(arr[i], i, arr);
}
}
通过回调函数将业务的重点聚焦在回调函数中,而不必每次都要重复编写遍历代码。
偏函数
作为将函数当做返回值输出的典型应用就是偏函数。所谓偏函数是指创建一个调用另外一个部分——参数或变量已经预置的函数——的函数的用法。反正看着定义我是没理解这东东干嘛的。咱们还是先看例子吧,偏函数最典型的例子就是类型判断。
Javascript对象都拥有三个属性:原型属性、类属性、可扩展性。(不知道的同学要回去翻犀牛书哦,page:138)类属性是一个字符串,Javascript中并未直接提供,但我们可以利用Object.prototype.toString来间接得到。该函数总是返回如下形式:
[object Class]
因此我们可以编写一系列isType函数。代码如下:
isString = function(obj){
return Object.prototype.toString.call(obj) === "[object String]";
}
isNumber = function(obj){
return Object.prototype.toString.call(obj) === "[object Number]";
}
isArray = function(obj){
return Object.prototype.toString.call(obj) === "[object Array]";
}
这几个函数中大部分代码是重复的,这时高阶函数便华丽丽的登场了:
isType = function(type) {
return function(obj) {
return Object.prototype.toString.call(obj) === "[object " + type + "]";
}
} isString = isType('String');
isNumber = isType('Number');
isArray = isType('Array');
所以通过指定部分参数来返回一个新的定制函数的形式就是偏函数。
currying(柯里化)
currying又称部分求值。一个currying的函数首先会接受一些参数,接受这些参数之后,函数并不会立即求值,而是继续返回另一个函数,刚才传入的参数在函数形成的闭包中被保存起来。待到函数被真正需要求值的时候,之前传入的所有参数都会被一次性用于求值。
var currying = function(fn) {
var args = []; return function() {
if (arguments.length === 0) {
return fn.applay(this, args);
} else {
args = args.concat(arguments);
return arguments.callee;
}
}
}
假设我们以计算一个月每天花销为例:
var currying = function(fn) {
debugger;
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())
事件节流
在某些场景下,某些事件可能会被重复的触发,但事件处理函数并不需要每次都执行。比如在window.resize事件中进行复杂的逻辑计算,如果用户频繁的改变浏览器大小,复杂计算会对性能造成严重影响;有时这些逻辑计算并不需要每次rezise时都触发,只需要计算有限的几次便可以。这时我们需要根据时间段来忽略一些事件请求。请看以下节流函数:
function throttle(fn, interval) {
var doing = false; return function() {
if (doing) {
return;
}
doing = true;
fn.apply(this, arguments);
setTimeout(function() {
doing = false;
}, interval);
}
} window.onresize = throttle(function(){
console.log('execute');
}, 500);
通过控制函数执行时间,可以在函数执行次数与功能需求之间达到完美平衡。另一个事件是mousemove。如果我们给一个dom元素绑定该事件,鼠标在改元素上移动时,该事件便会重复触发。
事件结束
对于某些可以频繁触发的事件,有时候我们希望在事件结束后进行一系列操作。这时我们可以利用高阶函数做如下处理:
function debounce(fn, interval) {
var timer = null; function delay() {
var target = this;
var args = arguments;
return setTimeout(function(){
fn.apply(target, args);
}, interval);
} return function() {
if (timer) {
clearTimeout(timer);
} timer = delay.apply(this, arguments);
}
};
window.onresize = throttle(function(){
console.log('resize end');
}, 500);
如果在这一过程中事件被触发则清除上一次事件句柄,重新绑定执行时间。
参考资料:
《深入浅出node》
《Javascript设计模式与开发实践》
Javascript:是你的高阶函数的更多相关文章
- JavaScript之闭包与高阶函数(一)
JavaScript虽是一门面向对象的编程语言,但同时也有许多函数式编程的特性,如Lambda表达式,闭包,高阶函数等. 函数式编程是种编程范式,它将电脑运算视为函数的计算.函数编程语言最重要的基础是 ...
- 《前端之路》之 JavaScript 进阶技巧之高阶函数(下)
目录 第二章 - 03: 前端 进阶技巧之高阶函数 一.防篡改对象 1-1:Configurable 和 Writable 1-2:Enumerable 1-3:get .set 2-1:不可扩展对象 ...
- JavaScript(1)高阶函数filter、map、reduce
前言 需求:有这样一个数组[10, 20, 110, 200, 60, 30, 40] 1.筛选出数组中小于100的元素 2.将筛选出的每个元素的值x2 3.完成第2步之后,将数组中的所有元素加起来 ...
- JavaScript高阶函数
所谓高阶函数(higher-order function) 就是操作函数的函数,它接收一个或多个函数作为参数,并返回一个新函数. 下面的例子接收两个函数f()和g(),并返回一个新的函数用以计算f(g ...
- JavaScript高阶函数 map reduce filter sort
本文是笔者在看廖雪峰老师JavaScript教程时的个人总结 高阶函数 一个函数就接收另一个函数作为参数,这种函数就称之为高阶函数 1.高阶函数之map: ...
- JavaScript高阶函数的应用
定义 高阶函数是指至少满足下列条件之一的函数: 函数可以作为参数被传递: 函数可以作为返回值输出. JavaScript语言中的函数显然满足高阶函数的条件,在实际开发中,无论是将函数当作参数传递,还是 ...
- JavaScript 高阶函数 + generator生成器
map/reduce map()方法定义在JavaScript的Array中,我们调用Array的map()方法,传入我们自己的函数,就得到了一个新的Array作为结果: function pow(x ...
- Javascript 闭包与高阶函数 ( 一 )
上个月,淡丶无欲 让我写一期关于 闭包 的随笔,其实惭愧,我对闭包也是略知一二 ,不能给出一个很好的解释,担心自己讲不出个所以然来. 所以带着学习的目的来写一写,如有错误,忘不吝赐教 . 为什么要有闭 ...
- Javascript 闭包与高阶函数 ( 二 )
在上一篇 Javascript 闭包与高阶函数 ( 一 )中介绍了两个闭包的作用. 两位大佬留言指点,下来我会再研究闭包的实现原理和Javascript 函数式编程 . 今天接到头条 HR 的邮件,真 ...
随机推荐
- Unix权限管理
// */ // ]]> Unix权限管理 Table of Contents 1 Unix权限管理 2 进程权限 3 文件权限 4 进程对文件的存取访问的权限校验过程 1 Unix权限管理 权 ...
- B-tree
2-3 Tree 二叉搜索树的每个节点只带有一个值,这个值将数据区间划分成两部分,值左边的部分(也就是小于这个值的数据)保存到节点的左子树,值右边的部分保存到节点的右子树.因此,每个非叶子节最多能够拥 ...
- 一点一滴学shell-Shell expr的用法 (转)
原文链接:http://desheng666.blog.163.com/blog/static/4908408220121643953425/ expr命令一般用于整数值,但也可用于字符串.一般格式为 ...
- 数据库优化系列——SQL性能优化十条建议
1.查询的模糊匹配 尽量避免在一个复杂查询里面使用 LIKE '%parm1%'—— 红色标识位置的百分号会导致相关列的索引无法使用,最好不要用. 解决办法: 其实只需要对该脚本略做改进,查询速度便 ...
- freeCodeCamp:Chunky Monkey
猴子吃香蕉可是掰成好几段来吃哦! 把一个数组arr按照指定的数组大小size分割成若干个数组块. 例如:chunk([1,2,3,4],2)=[[1,2],[3,4]]; chunk([1,2,3,4 ...
- 51nod 1138 连续整数的和(数学公式)
1138 连续整数的和 #include <iostream> #include <cmath> #include <cstdio> using namespace ...
- 计算机网路之动态NAT配置
配置路由端口的ip地址与打开(省略) 配置路由协议 router eigrp 100 network 211.1.1.0(网络号) 0.0.0.255(通配子掩) network 192.168.1. ...
- SQLServer数据库中创建临时表
IF object_id('tempdb..#jimmy') is not NULL BEGIN DROP TABLE #jimmy; END IF object_id('tempdb..#jimmy ...
- template学习一函数模板
要点: 1.模板参数在实体化的时候不能自动类型转换,只有非模板函数才可以 例如: int max(int,int); template <class T> T max(T,T); 在调用的 ...
- velocity模板入门
$!{velocityCount} 随机