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 相关文章推荐
JavaScript创建命名空间(namespace)的最简实现
Dec 11 Javascript
jQuery 图像裁剪插件Jcrop的简单使用
May 22 Javascript
JQuery Tips(2) 关于$()包装集你不知道的
Dec 14 Javascript
JS+CSS实现简易实用的滑动门菜单效果
Sep 18 Javascript
AngularJS基础 ng-mouseover 指令简单示例
Aug 02 Javascript
ionic实现带字的toggle滑动组件
Aug 27 Javascript
原生JS实现首页进度加载动画
Sep 14 Javascript
AngularJs入门教程之环境搭建+创建应用示例
Nov 01 Javascript
浅谈ES6新增的数组方法和对象
Aug 08 Javascript
JavaScript实现的九种排序算法
Mar 04 Javascript
vue+springboot图片上传和显示的示例代码
Feb 14 Javascript
基于vue实现探探滑动组件功能
May 29 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
Yii实现MySQL多数据库和读写分离实例分析
2014/12/03 PHP
PHP实现的redis主从数据库状态检测功能示例
2017/07/20 PHP
laravel5.1框架model类查询的实现方法
2019/10/08 PHP
CSDN轮换广告图片轮换效果
2007/03/27 Javascript
Jquery 插件开发笔记整理
2011/01/17 Javascript
jquery map方法使用示例
2014/04/23 Javascript
javascript判断是手机还是电脑访问网页的简单实例分享
2014/06/03 Javascript
jquery实现点击页面计算点击次数
2015/01/23 Javascript
jquery实现右键菜单插件
2015/03/29 Javascript
JavaScript对表格或元素按文本,数字或日期排序的方法
2015/05/26 Javascript
jQuery Validate 数组 全部验证问题
2017/01/12 Javascript
javascript编写简易计算器
2017/05/06 Javascript
基于vue.js 2.x的虚拟滚动条的示例代码
2018/01/23 Javascript
Vue中mintui的field实现blur和focus事件的方法
2018/08/25 Javascript
Python中title()方法的使用简介
2015/05/20 Python
django之session与分页(实例讲解)
2017/11/13 Python
Django中Forms的使用代码解析
2018/02/10 Python
Python实现的knn算法示例
2018/06/14 Python
Python中正则表达式的用法总结
2019/02/22 Python
详解Python 函数如何重载?
2019/04/23 Python
python 基于wx实现音乐播放
2020/11/24 Python
手把手教你用Django执行原生SQL的方法
2021/02/18 Python
HTML5 Video标签的属性、方法和事件汇总介绍
2015/04/24 HTML / CSS
adidas美国官网:adidas US
2016/09/21 全球购物
Hotter Shoes英国官网:英伦风格,舒适的鞋子
2017/12/28 全球购物
最新销售员个人自荐信
2013/09/21 职场文书
新驾驶员个人自我评价
2014/01/03 职场文书
运动会稿件50字
2014/02/17 职场文书
资助贫困学生倡议书
2014/05/16 职场文书
县政协领导班子群众路线教育实践活动四风问题整改方案
2014/10/26 职场文书
优秀教研组申报材料
2014/12/26 职场文书
爱国主义影片观后感
2015/06/18 职场文书
2016年大学生暑期社会实践方案
2015/11/26 职场文书
SQL Server连接查询的实用教程
2021/04/07 SQL Server
css 边框添加四个角的实现代码
2021/10/16 HTML / CSS
MySQL的存储过程和相关函数
2022/04/26 MySQL