zoukankan      html  css  js  c++  java
  • [转]深入理解闭包(二)

    闭包的定义,我们知道,无论通过何种手段,只要将内部函数传递到所在的词法作用域以外,它都会持有对原始作用域的引用,无论在何处执行这个函数都会使用闭包。接下来,本文将详细介绍闭包的10种形式 

    返回值

      最常用的一种形式是函数作为返回值被返回

    复制代码
    var F = function(){
        var b = 'local';
        var N = function(){
            return b;
        }
        return N;
    }
    console.log(F()());
    复制代码

    函数赋值

      一种变形的形式是将内部函数赋值给一个外部变量

    复制代码
    var inner;
    var F = function(){
        var b = 'local';
        var N = function(){
            return b;
        };
        inner = N;
    };
    F();
    console.log(inner());
    复制代码

    函数参数

      闭包可以通过函数参数传递函数的形式来实现

    复制代码
    var Inner = function(fn){
        console.log(fn());
    }
    var F = function(){
        var b = 'local';
        var N = function(){
            return b;
        }
        Inner(N);
    }
    F();
    复制代码

    IIFE

      由前面的示例代码可知,函数F()都是在声明后立即被调用,因此可以使用IIFE来替代。但是,要注意的是,这里的Inner()只能使用函数声明语句的形式,而不能使用函数表达式。详细原因移步至此

    复制代码
    function Inner(fn){
        console.log(fn());
    }
    
    (function(){
        var b = 'local';
        var N = function(){
            return b;
        }
        Inner(N);
    })();
    复制代码

    循环赋值

      在闭包问题上,最常见的一个错误就是循环赋值的错误。

    复制代码
    function foo(){
        var arr = [];
        for(var i = 0; i < 2; i++){
            arr[i] = function(){
                return i;
            }
        }
        return arr;
    }
    var bar = foo();
    console.log(bar[0]());//2    
    复制代码

      正确的写法如下

    复制代码
    function foo(){
        var arr = [];
        for(var i = 0; i < 2; i++){
            arr[i] = (function fn(j){
                return function test(){
                    return j;
                }
            })(i);
        }
        return arr;
    }
    var bar = foo();
    console.log(bar[0]());//0    
    复制代码

    g(s)etter

      我们通过提供getter()和setter()函数来将要操作的变量保存在函数内部,防止其暴露在外部

    复制代码
    var getValue,setValue;
    (function(){
        var secret = 0;
        getValue = function(){
            return secret;
        }
        setValue = function(v){
            if(typeof v === 'number'){
                secret = v;
            }
        }
    })();
    console.log(getValue());//0
    setValue(1);
    console.log(getValue());//1
    复制代码

    迭代器

      我们经常使用闭包来实现一个累加器

    复制代码
    var add = (function(){
        var counter = 0;
        return function(){
            return ++counter; 
        }
    })();
    console.log(add())//1
    console.log(add())//2  
    复制代码

      类似地,使用闭包可以很方便的实现一个迭代器

    复制代码
    function setup(x){
        var i = 0;
        return function(){
            return x[i++];
        }
    }
    var next = setup(['a','b','c']);
    console.log(next());//'a'
    console.log(next());//'b'
    console.log(next());//'c'
    复制代码

    区分首次

    复制代码
    var firstLoad = (function(){
      var _list = [];
      return function(id){
        if(_list.indexOf(id) >= 0){
          return false;
        }else{
          _list.push(id);
          return true;
        }
      }
    })();
    
    firstLoad(10);//true
    firstLoad(10);//false
    firstLoad(20);//true
    firstLoad(20);//false
    复制代码

    缓存机制

      通过闭包加入缓存机制,使得相同的参数不用重复计算,来提高函数的性能

      未加入缓存机制前的代码如下

    复制代码
    var mult = function(){
      var a = 1;
      for(var i = 0,len = arguments.length; i<len; i++){
        a = a * arguments[i];
      }
      return a;
    }
    复制代码

      加入缓存机制后,代码如下

    复制代码
    var mult = function(){
      var cache = {};
      var calculate = function(){
        var a = 1;
        for(var i = 0,len = arguments.length; i<len; i++){
          a = a * arguments[i];
        }
        return a;
      };
      return function(){
        var args = Array.prototype.join.call(arguments,',');
        if(args in cache){
          return cache[args];
        }
    return cache[args] = calculate.apply(null,arguments); } }()
    复制代码

    img对象

      img对象经常用于数据上报

    var report = function(src){
      var img = new Image();
      img.src = src;
    }
    report('http://xx.com/getUserInfo');

      但是,在一些低版本浏览器中,使用report函数进行数据上报会丢失30%左右的数据,也就是说,report函数并不是每一次都成功地发起了HTTP请求

      原因是img是report函数中的局部变量,当report函数的调用结束后,img局部变量随即被销毁,而此时或许还没来得及发出HTTP请求,所以此次请求就会丢失掉

      现在把img变量用闭包封闭起来,就能解决请求丢失的问题

    复制代码
    var report = (function(){
      var imgs = [];
      return function(src){
        var img = new Image();
        imgs.push(img);
        img.src = src;
      }
    })()
    report('http://xx.com/getUserInfo');
     
  • 相关阅读:
    政务公开系统专栏首页的跨站攻击漏洞
    Spring+XFire WSSecurity安全认证开发感悟
    Appfuse使用中遇到的问题及解决方案
    How to get the rowid when insert the data to Oracle database
    How to configure CVS in IntelliJ IDEA
    localhost打不开 127.0.0.1可以打开,,,或 hosts 文件不起作用的解决方法
    ASp.net中Froms验证方式
    ASP.NET 页面执行顺序详解
    【转】防止用户通过后退按钮重复提交表单ASP中的response.Buffer,Response.Expires,Response.CacheControl
    页面事件(Init,Load,PreRender)执行顺序__简单总结
  • 原文地址:https://www.cnblogs.com/xuzhudong/p/8945881.html
Copyright © 2011-2022 走看看