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设计模式与开发实践》

时间: 2024-11-07 01:24:23

Javascript:是你的高阶函数的相关文章

Effective JavaScript Item 19 使用高阶函数 (High-Order Function)

本系列作为Effective JavaScript的读书笔记. 不要被高阶函数这个名字给唬住了.实际上,高阶函数只是代表了两类函数: 接受其他函数作为参数的函数 返回值为函数的函数 有了这个定义,你也许就发现你已经使用过它们了,典型的就是对于一些事件的处理时传入的回调函数. 另外的一个典型使用场景就是Array类型的sort函数,它可以接受一个function作为排序时比较的判断依据: [3, 1, 4, 1, 5, 9].sort(function(x, y) { if (x < y) { r

JavaScript设计模式与开发实践-读书笔记(3)闭包和高阶函数

闭包(closure) 闭包的形成与变量的作用域以及变量的生存周期密切相关. 变量的作用域,就是指变量的有效范围. 全局变量和局部变量. 在JavaScript中,函数可以用来创造函数作用域. 变量的生存周期,全局变量的生命周期是永久的,除非我们主动销毁这个全局变量. 对于在函数体内用var关键字声明的局部变量来说,当退出函数时,这些局部变量即失去了它们的价值,它们都会随着函数调用的结束而被销毁. 利用闭包我们可以完成许多奇妙的工作. 闭包的作用: 1.封转变量 闭包可以帮助我们把一些不需要暴露

JavaScript设计模式与开发实践——读书笔记1.高阶函数(下)

上部分主要介绍高阶函数的常见形式,本部分将着重介绍高阶函数的高级应用. 1.currying currying指的是函数柯里化,又称部分求值.一个currying的函数会先接受一些参数,但不立即求值,而是继续返回给另一个函数,通过闭包存储起来.等到函数被真正需求要求值的时候,将之前传入的参数统一起来求值.例如,我们要计算一个月的开销,我们并不需要计算每天具体花了多少,而是需要计算月底总共花掉多少,也就是说,实际上我们只需要在月底计算一次.所以每个月的前29天,我们都只需要保存好当天的开销,到30

《JavaScript设计模式与开发》笔记 6.高阶函数

1.函数作为参数传递 1.回调函数 2.Array.prototype.sort 2.函数作为返回值输出 1.判断数据的类型 3.高级函数的实现AOP 4.高阶函数的其他应用 1.currying 函数柯里化 2.uncurring 3.函数节流 4.分时函数 5.惰性加载函数 1.函数作为参数传递 1.回调函数 最经常用的或许就是异步Ajax了 var getUserInfo = function(userId,callback){ $.ajax("http://xxx.com/getUser

JavaScript高阶函数

所谓高阶函数(higher-order function) 就是操作函数的函数,它接收一个或多个函数作为参数,并返回一个新函数. 下面的例子接收两个函数f()和g(),并返回一个新的函数用以计算f(g()); //返回一个新的可以计算f(g())的函数 //返回的函数h()将它所有的实参传入g(),然后将g()的返回值传入f() //调用f()和g()时的this值和调用h()时的this值是同一个this function compose(f,g){ return function(){ re

07.Javascript——入门高阶函数

高阶函数英文叫Higher-order function..JavaScript的函数其实都指向某个变量.既然变量可以指向函数,函数的参数能接收变量,那么一个函数就可以接收另一个函数作为参数,这种函数就称之为高阶函数. 一个最简单的高阶函数: function add(x, y, f) { return f(x) + f(y); } 当我们调用add(-5, 6, Math.abs)时,参数x,y和f分别接收-5,6和函数Math.abs,根据函数定义,我们可以推导计算过程为: x = -5;

javascript设计模式与开发实践阅读笔记(3)——高阶函数的其他应用

高阶函数的其他应用 1.currying 函数柯里化,又称部分求值,一个currying 的函数首先会接受一些参数,接受了这些参数之后,该函数并不会立即求值,而是继续返回另外一个函数,刚才传入的参数在函数形成的闭包中被保存起来.待到函数被真正需要求值的时候,之前传入的所有参数都会被一次性用于求值. var cost = (function(){ var args = []; return function(){ if ( arguments.length === 0 ){ var money =

JavaScript 高阶函数 + generator生成器

map/reduce map()方法定义在JavaScript的Array中,我们调用Array的map()方法,传入我们自己的函数,就得到了一个新的Array作为结果: function pow(x) { return x * x; } var arr = [1, 2, 3, 4, 5, 6, 7, 8, 9]; arr.map(pow); // [1, 4, 9, 16, 25, 36, 49, 64, 81] map()传入的参数是pow,即函数对象本身. 你可能会想,不需要map(),写

JavaScript高阶函数 map reduce filter sort

本文是笔者在看廖雪峰老师JavaScript教程时的个人总结 高阶函数 一个函数就接收另一个函数作为参数,这种函数就称之为高阶函数 1.高阶函数之map: 此时我们有一个数组和一个接受一个参数并返回一个数的函数.我们需要把这个数组的每一个值在这个函数上走一遍,从而得到一个新数组.此时就需要map了 var a = [1,2,3,4,5,6]; var b = [] var fun = function(x) { return x * x; } b = a.map(fun) alert(b)  /