高级技巧(2)——函数柯里化

高级技巧(2)——函数柯里化

函数柯里化
  • 复习
    2、addHandler (),他的职责是分情况使用DOM0级方法、DOM2级方法或IE方法来添加事件。这个方法属于一个名字叫EventUtil的对象,可以使用这个对象来处理浏览器间的差异。addHandler() 方法接受3个参数:要操作的元素、时间名称和事件处理程序函数
    3、removeHandler(),它也接受相同参数。这个方法的指责是移除之前添加的事件处理程序,无论该事件处理程序是采取什么方式添加到元素中的。如果其他方法无效,默认采用DOM0级方法

  • 概念
    在这里插入图片描述

  • 一个简单的引例

// 普通的add函数
function add(x, y) {
    return x + y
}

// 柯里化以后
function curryingAdd(x) {
    return function (y) {
        return x + y
    }
}

add(1, 2)           // 3
curryingAdd(1)(2)   // 3
  • 解释:上面我们可以看到第一个普通的相加函数很容易理解,但是第二个函数是柯里化以后即将普通函数的2个参数先用一个函数接收了第一个参数,再返回一个函数去处理第二个参数,意思差不多就是封装了一层
  • 与bind()函数:(在上一个博客高级技巧一中已经介绍了函数绑定和bind函数):函数柯里化就被作为函数绑定的一部分去构造更复杂的bind()函数
    • 举例
function bind(fn, context){
var args = Array.prototype.slice.call(arguments, 2);
return function(){
var innerArgs = Array.prototype.slice.call(arguments);
var finalArgs = args.concat(innerArgs);
return fn.apply(context, finalArgs);
};
}
  • 自己通用的封装方法
// 初步封装
var currying = function(fn) {
    // args 获取第一个方法内的全部参数
    var args = Array.prototype.slice.call(arguments, 1)
    return function() {
        // 将后面方法里的全部参数和args进行合并
        var newArgs = args.concat(Array.prototype.slice.call(arguments))
        // 把合并后的参数通过apply作为fn的参数并执行
        return fn.apply(this, newArgs)
    }
}
  • 复习:slice()方法
    在这里插入图片描述

  • 例子的解析

    • 1、参数解释:curry() 的第一个参数是要进行柯里化的函数,其他参数是要传入的值
    • 2、获取:获取第一个参数之后的所有参数:对arguments对象运用slice()方法,并传入参数 1 表示被返回的数组包含从第二个参数开始的所有参数
    • 3、存放所有参数newArgs数组将所有内部函数和外部函数的参数数组组合起来
    • 4、传递结果:用apply函数,此处考虑到了执行环境,用的this
  • 函数柯里化的好处:

    • 参数复用(正则表达式验证举例:

    • 构造bind函数

      • 复习:1、arguments
// arguments 是一个对应于传递给函数的参数的类数组对象
  function a(){
    console.log(arguments);
  }
  a(); // Arguments [callee: ƒ, Symbol(Symbol.iterator): ƒ]
  a(1,2,3); // Arguments(3) [1, 2, 3, callee: ƒ, Symbol(Symbol.iterator): ƒ]
  • 2、 ==bind()==方法主要就是将函数绑定到某个对象,bind()会创建一个函数,函数体内的this对象的值会被绑定到传入bind()中的第一个参数的值

  • 参数复用举例:

// 正常正则验证字符串 reg.test(txt)

// 函数封装后
function check(reg, txt) {
    return reg.test(txt)
}

check(/\d+/g, 'test')       //false
check(/[a-z]+/g, 'test')    //true

// Currying后
function curryingCheck(reg) {
    return function(txt) {
        return reg.test(txt)
    }
}

var hasNumber = curryingCheck(/\d+/g)
var hasLetter = curryingCheck(/[a-z]+/g)

hasNumber('test1')      // true
hasNumber('testtest')   // false
hasLetter('21212')      // false
  • 解析:这个正则校验只要用check函数就行了,但是如果要校验较多的话,需要将第一个参数进行复用,这样别的地方就能够直接调用hasNumber,hasLetter等函数,让参数能够复用

  • 性能:

    • 1、存取arguments对象通常要比存取命名参数要慢一点
    • 2、一些老版本的浏览器在arguments.length的实现上是相当慢的
    • 3、使用fn.apply( … ) 和 fn.call( … )通常比直接调用fn( … ) 稍微慢点
    • 4、创建大量嵌套作用域和闭包函数会带来花销,无论是在内存还是速度上(一直有提到过这个点)

——参考于https://www.jianshu.com/p/2975c25e4d71

摘录:JavaScript 中的柯里化函数和绑定函数提供了强大的动态函数创建功能。使用 ==bind() 还是 curry()==要根据是否需要 object 对象响应来决定。它们都能用于创建复杂的算法和功能,当然两者都不应滥用,因为每个函数都会带来额外的开销——《JavaScript高级程序设计》

  • 扩展题目:
// 实现一个add方法,使计算结果能够满足如下预期:
add(1)(2)(3) = 6;
add(1, 2, 3)(4) = 10;
add(1)(2)(3)(4)(5) = 15;

function add() {
    // 第一次执行时,定义一个数组专门用来存储所有的参数
    var _args = Array.prototype.slice.call(arguments);

    // 在内部声明一个函数,利用闭包的特性保存_args并收集所有的参数值
    var _adder = function() {
        _args.push(...arguments);
        return _adder;
    };

    // 利用toString隐式转换的特性,当最后执行时隐式转换,并计算最终的值返回
    _adder.toString = function () {
        return _args.reduce(function (a, b) {
            return a + b;
        });
    }
    return _adder;
}

add(1)(2)(3)                // 6
add(1, 2, 3)(4)             // 10
add(1)(2)(3)(4)(5)          // 15
add(2, 6)(1)                // 9

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值