Java教程

闭包

本文主要是介绍闭包,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

闭包

闭包就是一个函数引用另一个函数的变量,因为变量被引用着所以不会被回收,因此可以用来封装一个私有变量。这是优点也是缺点,不必要的闭包只会增加内存消耗。或者说闭包就是子函数可以使用父函数的局部变量,还有父函数的参数。

最近在学ES6,学了let,突然想起一个我以前遇到的bug,相信也有很多同学也遇到过同样的bug。我们先看看下面的代码:

//html、js代码
  <body>
	<button>a</button>
	<button>b</button>
	<button>c</button>
</body>

<script type="text/javascript">
	var btn = document.getElementsByTagName('button');
	for(var i = 0 ; i<btn.length;i++)
	{
		btn[i].onclick = function () {
			alert(i);
		}
	}
	</script>

我们运行这段代码,在按a这个按钮,会弹出什么?也许没碰到这个bug的会认为 弹出一个 ‘0’ ,但是 弹出的是 3 。

为什么弹出的是3?
 在这里就要引入js闭包的概念。闭包,闭包就是能够读取其他函数内部变量的函数,在js中,函数(function)每次创建&emsp的时候都会生成一个闭包,这个闭包包含这个函数能访问的所有变量,闭包的一个意义在于可以让内部函数访问外部函数变量的作用域。

在这段代码中三个btn[i].onclick就创建了三个闭包,但是这三个闭包引用了同一个变量的作用域,那就是 i ,一个 i 被三个引用那肯定是会出问题的。

讲到这里,对于学c++或java的同学肯定会觉得不可理喻的,不就一个简单的for循环吗?怎么会出问题呢?当事实上它就是出问题了。
  在se6还未诞生前,js没有块级作用域的说法,而在java、c++块级作用域是很常见的。

问题在于var,var定义的变量是有提升作用的,会自动提升成函数级作用域,而上述js代码中的 i 就被提升为全局变量了,所以不难理解为什么会三个函数同时引用同一个 i 了。

如何解决?
 正常我们应该用 (function (i){ })(i); 即先创建一个匿名函数再调用这个函数。代码如下:

<body>
	<button>a</button>
	<button>b</button>
	<button>c</button>
</body>
<script type="text/javascript">
	var btn1 = document.getElementsByTagName('button');
	for (var i = 0; i < btn1.length; i++) {
		(function (t){
			btn1[t].onclick = function () {
			alert(t);
		}
		})(i)
	}
</script>

ES6中的let
 let定义的变量:是块级作用域,不能重复定义。let的引入,可以让我们无形中解决一些bug。个人觉得还是有必要要用的。
 有了let之后我们把var i ; 改为 let i;就没问题了,完美的解决了var这个函数级作用域的问题。

再讲讲闭包
  闭包个人觉得有两大用处。
 第一是为了让内部函数能调用外部函数的变量,从而使内部函数更加有意义。
 第二是为了私有化变量,在java中有私有成员变量、私有局部变量,私有的存在让一个类有成为完美封装的存在,这个是java三大特点之一 封装。但是,js中没有 private 访问权限符,那怎么办?答案是闭包。

var Counter = (function() {
  var privateCounter = 0;
  function changeBy(val) {
    privateCounter += val;
  }
  return {
    increment: function() {
      changeBy(1);
    },
    decrement: function() {
      changeBy(-1);
    },
    value: function() {
      return privateCounter;
    }
  }   
})();

上述代码就将privateCouter进行了闭包、封装,让privateCouter无法直接被访问、修改。

补充: 块级作用域,在每次遇到块(即中括号)时,会将 i 的引用取消,重新申请一个 i 的引用(但这个 i 不会被销毁,因为js的垃圾内存回收机制,i还存在闭包中的click的引用,emmmm有点低性能的感觉)。

这篇关于闭包的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!