Javascript 是你的高阶函数(高级应用)


Posted in Javascript onJune 15, 2015

在通常的编程语言中,函数的参数只能是基本类型或者对象引用,返回值也只是基本数据类型或对象引用。但在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 相关文章推荐
编写兼容IE和FireFox的脚本
May 18 Javascript
修复bash漏洞的shell脚本分享
Dec 31 Javascript
vue2.0开发实践总结之疑难篇
Dec 07 Javascript
JavaScript利用闭包实现模块化
Jan 13 Javascript
利用js查找数组中指定元素并返回该元素的所有索引示例
Mar 29 Javascript
jQuery插件FusionCharts绘制2D环饼图效果示例【附demo源码】
Apr 10 jQuery
vue2.0移除或更改的一些东西(移除index key)
Aug 28 Javascript
本地搭建微信小程序服务器的实现方法
Oct 27 Javascript
Bootstrap标签页(Tab)插件切换echarts不显示问题的解决
Jul 13 Javascript
vue中datepicker的使用教程实例代码详解
Jul 08 Javascript
Vue.js组件通信之自定义事件详解
Oct 19 Javascript
js实现旋转的星空效果
Nov 01 Javascript
Javascript 高阶函数使用介绍
Jun 15 #Javascript
jQuery预加载图片常用方法
Jun 15 #Javascript
简述JavaScript中正则表达式的使用方法
Jun 15 #Javascript
简介JavaScript中用于处理正切的Math.tan()方法
Jun 15 #Javascript
在JavaScript中使用开平方根的sqrt()方法
Jun 15 #Javascript
JavaScript中的Math.sin()方法使用详解
Jun 15 #Javascript
JavaScript中用于四舍五入的Math.round()方法讲解
Jun 15 #Javascript
You might like
谷歌音乐搜索栏的提示功能php修正代码
2011/05/09 PHP
php 保留字列表
2012/10/04 PHP
解析php DOMElement 操作xml 文档的实现代码
2013/05/10 PHP
PHP获取栏目的所有子级和孙级栏目的ID号示例
2014/04/01 PHP
PHP获取当前所在目录位置的方法
2014/11/26 PHP
PHP+MySQL删除操作实例
2015/01/21 PHP
非集成环境的php运行环境(Apache配置、Mysql)搭建安装图文教程
2016/04/12 PHP
javascript下IE与FF兼容函数收集
2008/09/17 Javascript
用apply让javascript函数仅执行一次的代码
2010/06/27 Javascript
JS对象转换为Jquery对象实现代码
2013/12/29 Javascript
浏览器检测JS代码(兼容目前各大主流浏览器)
2016/02/21 Javascript
jquery中validate与form插件提交的方式小结
2016/03/26 Javascript
从零开始学习Node.js系列教程三:图片上传和显示方法示例
2017/04/13 Javascript
微信小程序 setData的使用方法详解
2017/04/20 Javascript
vue中进入详情页记住滚动位置的方法(keep-alive)
2018/09/21 Javascript
如何封装了一个vue移动端下拉加载下一页数据的组件
2019/01/06 Javascript
Electron vue的使用教程图文详解
2019/07/05 Javascript
[31:00]2014 DOTA2华西杯精英邀请赛5 24 NewBee VS iG
2014/05/25 DOTA
[00:12]2018DOTA2亚洲邀请赛SOLO赛 MidOne是否中单第一人?
2018/04/05 DOTA
Python中的ConfigParser模块使用详解
2015/05/04 Python
利用标准库fractions模块让Python支持分数类型的方法详解
2017/08/11 Python
python用户管理系统的实例讲解
2017/12/23 Python
Linux下Pycharm、Anaconda环境配置及使用踩坑
2018/12/19 Python
在Python 中同一个类两个函数间变量的调用方法
2019/01/31 Python
django+echart数据动态显示的例子
2019/08/12 Python
python数据类型之间怎么转换技巧分享
2019/08/20 Python
Python 如何提高元组的可读性
2019/08/26 Python
浅谈Python线程的同步互斥与死锁
2020/03/22 Python
css3简单练习实现遨游浏览器logo的绘制
2013/01/30 HTML / CSS
澳大利亚汽车零部件、音响及配件超市:Automotive Superstore
2018/06/19 全球购物
八一建军节部队活动方案
2014/02/04 职场文书
IT工程师岗位职责
2014/07/04 职场文书
正风肃纪查摆剖析材料
2014/10/10 职场文书
毕业设计致谢词
2015/05/14 职场文书
入学证明
2015/06/23 职场文书
深入理解以DEBUG方式线程的底层运行原理
2021/06/21 Java/Android