zoukankan      html  css  js  c++  java
  • 柯里化与反柯里化

    柯里化

    什么是柯里化

    柯里化(英语:Currying),是把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,并且返回接受余下的参数而且返回结果的新函数的技术。

    柯里化的基础

    上面的代码其实是一个高阶函数(high-order function), 高阶函数是指操作函数的函数,它接收一个或者多个函数作为参数,并返回一个新函数。此外,还依赖与闭包的特性,来保存中间过程中输入的参数。即:

    • 函数可以作为参数传递
    • 函数能够作为函数的返回值
    • 闭包

     

    通用实现

        var currying = function(fn) {
            //保存最初函数的第一个参数
            var args = [].slice.call(arguments, 1);
            return function() {
                //将第一个参数与剩余的参数连接
                var newArgs = args.concat([].slice.call(arguments));
                return fn.apply(null, newArgs);
            };
        };

     

    柯里化的作用

    参数复用

        var countNum = currying(function() {
            var allargs = [].slice.call(arguments);
            console.log(allargs.join(";"));
        }, "10");
    
        countNum("1","2","3");    //10;1;2;3
    
        countNum("4","5");        //10;4;5;

    延迟计算

        var currying = function( fn ){
            var args = [];
            return function(){
                if ( arguments.length === 0 ){
                    return fn.apply( this, args );
                }else{
                   args = args.concat([].slice.call(arguments))
                }
            }
        };
        var cost = (function(){
            var money = 0;
            return function(){
                for ( var i = 0, l = arguments.length; i < l; i++ ){
                    money += arguments[ i ];
                }
                return money;
            }
        })();
    
        var cost = currying( cost ); // 转化成currying 函数
        cost( 100 ); // 未真正求值
        cost( 200 ); // 未真正求值
        cost( 300 ); // 未真正求值
        alert ( cost() ); // 求值并输出:600

    提前返回

    var addEvent = (function(){
        if (window.addEventListener) {
            return function(el, sType, fn, capture) {
                el.addEventListener(sType, function(e) {
                    fn.call(el, e);
                }, (capture));
            };
        } else if (window.attachEvent) {
            return function(el, sType, fn, capture) {
                el.attachEvent("on" + sType, function(e) {
                    fn.call(el, e);
                });
            };
        }
    })();

    反柯里化

      反柯里化函数,从字面讲,意义和用法跟函数柯里化相比正好相反,扩大适用范围,创建一个应用范围更广的函数。

      我们常用apply、call让对象去借用一个原本不属于它的方法,例如使用Array.prototype中的slice、push等方法操作数组,这是因为在javascript里面,很多函数都不做对象的类型检测,而是只关心这些对象能做什么。

    通用实现

        Function.prototype.uncurrying = function () {
            var self = this;
            return function() {
                var obj = Array.prototype.shift.call( arguments );
                return self.apply( obj, arguments );
            };
        };

    或者

        Function.prototype.uncurrying = function(){
            var self = this;
            return function(){
                return Function.prototype.call.apply( self, arguments );
            }
        };

    反柯里化的作用

      使本来只有特定对象才适用的方法,扩展到更多的对象。把原来已经固定的参数或者this上下文等当作参数延迟到未来传递。

        obj.foo( arg1 ) //foo本来是只在obj上的函数. 就像push原本只在Array.prototype上
        foo( obj, arg1 ) // 将[].push转换成push( [] )

    对arguments使用push 

        Function.prototype.uncurrying = function () {
            var self = this;     //self为push函数
            return function() {
                var obj = Array.prototype.shift.call( arguments );  //obj为 {"length": 1, "0": 1};
                return self.apply( obj, arguments );
                //相当于Array.prototype.push.apply(obj, 2)
            };
        };
    
        var push = Array.prototype.push.uncurrying();
        var obj = {
            "length": 1,
            "0": 1
        };
    
        push( obj, 2 );
        console.log( obj ); // 输出:{0: 1, 1: 2, length: 2}

    把Array.prototype的其他方法“复制”array对象

        for ( var i = 0, fn, ary = [ 'push', 'shift', 'forEach' ]; fn = ary[ i++ ]; ){
            Array[ fn ] = Array.prototype[ fn ].uncurrying();
        };
        var obj = {
            "length": 3,
            "0": 1,
            "1": 2,
            "2": 3
        };
    
        Array.push( obj, 4 ); // 向对象中添加一个元素
        console.log( obj.length ); // 输出:4
        var first = Array.shift( obj ); // 截取第一个元素
        console.log( first ); // 输出:1
        console.log( obj ); // 输出:{0: 2, 1: 3, 2: 4, length: 3}
    
        Array.forEach( obj, function( i, n ){
            console.log( n ); // 分别输出:0, 1, 2
        });

    对arguments使用slice方法

    var slice = Array.prototype.slice.uncurrying();
    
    (function(){
         alert( slice(arguments, 2) );    // [3, 4]
    })(1, 2, 3, 4)
  • 相关阅读:
    html基础教程2
    HTML的基础教程
    JS中响应函数和for循环执行问题
    Cookie显示上次访问时间出现错误的问题
    完全卸载VSCode--解决卸载重新安装后还有原来配置的问题
    servlet中输出HTML标签浏览器不能正常显示
    Java中Servlet输出中文乱码问题
    eclipse下配置Tomcat(没有Tomcat8及以上版本问题)
    Java多线程通信之wait()和notify()方法
    Java中synchronize关键字
  • 原文地址:https://www.cnblogs.com/surahe/p/6008258.html
Copyright © 2011-2022 走看看