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 相关文章推荐
jQuery 第二课 操作包装集元素代码
Mar 14 Javascript
jQuery图片预加载 等比缩放实现代码
Oct 04 Javascript
script不刷新页面的联动前后代码
Sep 18 Javascript
简单的JavaScript互斥锁分享
Feb 02 Javascript
对类Vue的MVVM前端库的实现代码
Sep 07 Javascript
vue-router的使用方法及含参数的配置方法
Nov 13 Javascript
深入理解Node内建模块和对象
Mar 12 Javascript
node中使用es6/7/8(支持性与性能)
Mar 28 Javascript
JS使用cookie保存用户登录信息操作示例
May 30 Javascript
JavaScript 函数用法详解【函数定义、参数、绑定、作用域、闭包等】
May 12 Javascript
el-form 多层级表单的实现示例
Sep 10 Javascript
vue+element table表格实现动态列筛选的示例代码
Jan 14 Vue.js
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
ThinkPHP模板输出display用法分析
2014/11/26 PHP
PHP Echo字符串的连接格式
2016/03/07 PHP
自动更新作用
2006/10/08 Javascript
javascript 命名空间以提高代码重用性
2008/11/13 Javascript
innerText和innerHTML 一些问题分析
2009/05/18 Javascript
jqPlot 基于jquery的画图插件
2011/04/26 Javascript
JavaScript实现可拖拽的拖动层Div实例
2015/08/05 Javascript
js+css绘制颜色动态变化的圈中圈效果
2016/01/27 Javascript
AngularJS ng-controller 指令简单实例
2016/08/01 Javascript
jQuery实现鼠标跟随效果
2017/02/20 Javascript
详解Vue使用命令行搭建单页面应用
2017/05/24 Javascript
利用ES6的Promise.all实现至少请求多长时间的实例
2017/08/28 Javascript
vue自定义filters过滤器
2018/04/26 Javascript
JS实现动态生成html table表格的方法分析
2018/07/11 Javascript
vue项目打包部署_nginx代理访问方法详解
2018/09/20 Javascript
js cavans实现静态滚动弹幕
2020/05/21 Javascript
JavaScript 常见的继承方式汇总
2020/09/17 Javascript
手把手教你如何编译打包video.js
2020/12/09 Javascript
Python八大常见排序算法定义、实现及时间消耗效率分析
2018/04/27 Python
Python Dataframe 指定多列去重、求差集的方法
2018/07/10 Python
Selenium(Python web测试工具)基本用法详解
2018/08/10 Python
python3 logging日志封装实例
2020/04/08 Python
英国最大的百货公司:Harrods
2016/08/18 全球购物
洛杉矶生活休闲而精致的基础品牌:Mika Jaymes
2018/01/07 全球购物
理肤泉俄罗斯官网:La Roche-Posay俄罗斯
2018/07/24 全球购物
华硕新加坡官方网上商店:ASUS Singapore
2020/07/09 全球购物
工地门卫岗位职责
2013/12/30 职场文书
公司薪酬管理制度
2014/01/31 职场文书
小学生获奖感言范文
2014/02/02 职场文书
应届毕业生通用的自荐书范文
2014/02/07 职场文书
《雨霖铃》听课反思
2014/02/13 职场文书
经典禁毒标语
2014/06/16 职场文书
2015年党员发展工作总结
2015/05/13 职场文书
python 爬取京东指定商品评论并进行情感分析
2021/05/27 Python
关于python中模块和重载的问题
2021/11/02 Python
Python Matplotlib库实现画局部图
2021/11/17 Python