前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Javascript 闭包学习

Javascript 闭包学习

原创
作者头像
ranky
发布2019-04-29 14:28:41
5280
发布2019-04-29 14:28:41
举报
文章被收录于专栏:Coding改变生活Coding改变生活

闭包

函数

说到函数,就不可避免的涉及到作用域问题,JS中把变量作用域分为全局和局部,所有函数均可访问全局变量,局部变量在函数体内使用,其他函数不能调用,并且函数执行完成会被清理。

代码语言:txt
复制
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。

代码语言:txt
复制
var count = 0;
function add()
{
	count ++;
}

首先想到的就是这种方式,这种方式必须定义一个全局变量count来存储每次调用add后的数量,使用过多的全局变量会造成全局变量污染,在一个较大的工程中,往往稍不注意就会使用一个已经被定义的变量,这时候容易造成运行问题?那要怎么解决计数问题呢?如果我们把计数变量放到函数体内定义会怎么样呢?看下下面的一个例子:

代码语言:txt
复制
var add = (function (){
		var count = 0;
        return function(){
            return count++;
        }
	})();

add();
add();
add();
console.log(add());  // 输出3

上面的例子中,在函数体内定义了count变量,这个变量在函数外不可被访问,因此“安全”。在函数体内又返回了一个函数,这个函数是被引用的,外层函数执行完后这个函数内存并没有被释放,而内层函数引用了外层函数中定义的变量count,因此外层函数析构的时候并没有释放count,count值被保留了下来,可以继续访问。

现在给下闭包的定义:返回函数内部变量的函数,让内存函数与外层函数建立联系,然后返回内层函数。

除此之外,闭包还有其他的几种用途,列举如下:

闭包的使用场景

1.减少使用全局变量,全局变量使用过多可能造成全局污染

2.需要取得计算的中间结果

3.环境上下文改变,导致函数运行非预期

利用函数闭包计算斐波那契数列(取得计算中间结果)

代码语言:txt
复制
//递归版本
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次,在很多情况下,递归代码逻辑结构虽然比较清晰,但是执行效率却不如非递归版本(递归将将每一层递归函数都压入栈中了)

给一组button添加监听事件(环境上下文改变)

给到这个问题的时候,我们会觉得这个问题非常简单,立马开始动手写代码,如下:

代码语言:txt
复制
	for(let i = 0; (i<3) ; i++)
	{
		document.getElememtById('btn_'+i).addEventListener('onclick',function(){
			//balabala
			alert(i);
		});
	}

嗯,大功告成!Emmm...仔细看下这个是有问题的,添加事件后,i的值始终为3,点击后test的参数也为3。为什么呢?因为js作用域的问题,因此使用闭包可以解决这个问题。

代码语言:txt
复制
	document.getElememtById('btn_'+i).addEventListener('onclick',(function(i){
			return function{
				alert(i);
			}
		})(i));

放到页面中去试试?嗯,现在才是大功告成。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 闭包
    • 函数
      • 闭包的使用场景
        • 利用函数闭包计算斐波那契数列(取得计算中间结果)
          • 给一组button添加监听事件(环境上下文改变)
          领券
          问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档