说到函数,就不可避免的涉及到作用域问题,JS中把变量作用域分为全局和局部,所有函数均可访问全局变量,局部变量在函数体内使用,其他函数不能调用,并且函数执行完成会被清理。
var a = 1;
function print0()
{
var a = 2;
var b = 3;
console.log(a); //2
}
function print1()
{
console.log(a); // 1
console.log(b); // undifined
}
为了说明闭包的,抛出一个问题:实现一个计数器,每次调用计数器加1。
var count = 0;
function add()
{
count ++;
}
首先想到的就是这种方式,这种方式必须定义一个全局变量count来存储每次调用add后的数量,使用过多的全局变量会造成全局变量污染,在一个较大的工程中,往往稍不注意就会使用一个已经被定义的变量,这时候容易造成运行问题?那要怎么解决计数问题呢?如果我们把计数变量放到函数体内定义会怎么样呢?看下下面的一个例子:
var add = (function (){
var count = 0;
return function(){
return count++;
}
})();
add();
add();
add();
console.log(add()); // 输出3
上面的例子中,在函数体内定义了count变量,这个变量在函数外不可被访问,因此“安全”。在函数体内又返回了一个函数,这个函数是被引用的,外层函数执行完后这个函数内存并没有被释放,而内层函数引用了外层函数中定义的变量count,因此外层函数析构的时候并没有释放count,count值被保留了下来,可以继续访问。
现在给下闭包的定义:返回函数内部变量的函数,让内存函数与外层函数建立联系,然后返回内层函数。
除此之外,闭包还有其他的几种用途,列举如下:
1.减少使用全局变量,全局变量使用过多可能造成全局污染
2.需要取得计算的中间结果
3.环境上下文改变,导致函数运行非预期
//递归版本
function fibonacci(n)
{
if(n == 1) return 1;
if(n == 0) return 0;
if(n <= 0) return null;
return fibonacci(n-1) + fibonacci(n-2);
}
fibonacci(10) //输出55,执行177次
//递归闭包版本
var fibonacci2 = (function()
{
let arr=[0,1,1];
return function(n){
if(arr[n])
return arr[n];
else{
arr[n] = fibonacc2i(n-1) + fibonacci2(n-2);
}
return arr[n];
}
})();
fibonacci2(10) //输出55,执行17次!
//非递归版本
var fibonacci3 = (function()
{
let arr = [0,1];
return function(n){
if(n <= 0) return 0;
if(n == 1) return 1;
let res = 0;
for(let i = 1;(i < n); i++)
{
res = arr[0] + arr[1];
arr[0] = arr[1];
arr[1] = res;
}
return res;
}
})();
fibonacci3(10) //输出55,for循环执行9次!
fabonacci2中利用函数闭包,将计算的中间结果存储下来了。fabonacci3中利用闭包存储上一次计算的值,非递归版本只需要执行9次,在很多情况下,递归代码逻辑结构虽然比较清晰,但是执行效率却不如非递归版本(递归将将每一层递归函数都压入栈中了)
给到这个问题的时候,我们会觉得这个问题非常简单,立马开始动手写代码,如下:
for(let i = 0; (i<3) ; i++)
{
document.getElememtById('btn_'+i).addEventListener('onclick',function(){
//balabala
alert(i);
});
}
嗯,大功告成!Emmm...仔细看下这个是有问题的,添加事件后,i的值始终为3,点击后test的参数也为3。为什么呢?因为js作用域的问题,因此使用闭包可以解决这个问题。
document.getElememtById('btn_'+i).addEventListener('onclick',(function(i){
return function{
alert(i);
}
})(i));
放到页面中去试试?嗯,现在才是大功告成。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。