欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

深入理解闭包系列第五篇——闭包的10种形式

程序员文章站 2024-02-19 15:18:28
...

前面的话

  根据闭包的定义,我们知道,无论通过何种手段,只要将内部函数传递到所在的词法作用域以外,它都会持有对原始作用域的引用,无论在何处执行这个函数都会使用闭包。接下来,本文将详细介绍闭包的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');

 


更多专业前端知识,请上【猿2048】www.mk2048.com
相关标签: javascript总结