闭包 柯里化

什么是闭包

  • 闭包是指有权访问另一个函数作用域中的变量的函数,
    创建闭包的最常见的方式就是在一个函数内创建另一个函数,通过另一个函数访问这个函数的局部变量

    function fn1(){
                var a=1;
                // 因为返回的函数被存储在全局变量中,
                // 并且这个返回的函数使用这个a的局部变量,因此a被保存在堆中
                //闭包会产生内存泄漏
                return function(){
                    a++;
                    console.log(a);
                }
            }
    
    
            var f=fn1();
            f()
            f(); 
    

闭包的特点和优点

闭包的特点

  1. 函数嵌套函数
  2. 函数内部可以引用外部的参数和变量
  3. 参数和变量不会被垃圾回收机制回收

闭包的优点

  1. 避免全局变量的污染
  2. 为了得到私有变量
  3. 希望一个变量长期驻扎在内存中

闭包的缺点

  1. 会造成内存泄漏
var Utils=(function(){
         var num=0;
            return {
                a:function(){
                    num++;
                    console.log(num);
                },
                b:function(){

                }
            }
        })();
        

        Utils.a();
        Utils.a();
        Utils.a();

柯里化

什么是柯里化

  • 就是指的把一个多参数的函数转化为单参数函数的方法

  • 收集参数进行存储,没有参数时执行要处理的实际函数

function curry(fn){
        var arr=[];
        return function(){
            if(arguments.length>0){//有参数传入
                arr=arr.concat(Array.from(arguments));//将arguement转化为数组放进去
                return arguments.callee;//自身函数
            }else{//没有传参
               return  fn.apply(null,arr);
            }
           
        }
    }

    function fns(){//解决实际融合问题
        return Array.from(arguments).reduce((value,item)=>value+=item);//求和
    }


  var s=fns(1,2,3,4,5,6)
    console.log(s);
    var sum=curry(fns);
   var s=sum(1)(2,3)(4,5,6)()
   console.log(s);

柯里化优点

  • 1.参数复用
// 正常正则验证字符串 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
  • 2.提前确认
  • 3.延迟运行
Function.prototype.bind = function (context) {
    var _this = this
    var args = Array.prototype.slice.call(arguments, 1)
 
    return function() {
        return _this.apply(context, args)
    }
}//bind是柯里化

封装方法

// 初步封装
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)
    }
}

// 支持多参数传递
function progressCurrying(fn, args) {

    var _this = this
    var len = fn.length;
    var args = args || [];

    return function() {
        var _args = Array.prototype.slice.call(arguments);
        Array.prototype.push.apply(args, _args);

        // 如果参数个数小于最初的fn.length,则递归调用,继续收集参数
        if (_args.length < len) {
            return progressCurrying.call(_this, fn, _args);
        }

        // 参数收集完毕,则执行fn
        return fn.apply(this, _args);
    }
}

柯里化性能

  • 存取arguments对象通常要比存取命名参数要慢一点
  • 一些老版本的浏览器在arguments.length的实现上是相当慢的
  • 使用fn.apply( … ) 和 fn.call( … )通常比直接调用fn( … ) 稍微慢点
  • 创建大量嵌套作用域和闭包函数会带来花销,无论是在内存还是速度上
  • 其实在大部分应用中,主要的性能瓶颈是在操作DOM节点上,这js的性能损耗基本是可以忽略不计的,所以curry是可以直接放心的使用。

反柯里化

  • 意义和用法跟函数柯里化相比正好相反,扩大适用范围,创建一个应用范围更广的函数。使本来只有特定对象才适用的方法,扩展到更多的对象

猜你喜欢

转载自blog.csdn.net/w_cyj/article/details/107991733