五个简单例子,明白闭包原理
2017-09-22 11:13
246 查看
闭包一直是许多初学者的难题,网上对闭包的讲解也是众说纷纭,但还是许多人不能明白。
下面我通过五个简单例子,解释闭包原理。
第一个例子
第二个例子
第二个例子:将i定义在函数内部,会发现 i 这时候无法实现累加,一直显示是1。这是为什么?
---------------------------------------------------------
原因是:
1、第一个例子的 i 定义在函数外面,它在一个叫做"全局作用域"的区域里面。"全局作用域"只会在浏览器窗口关闭或页面刷新的时候进行关闭。(我们跟第二个例子对比下就知道全局作用域)。
2、第二个例子的 i 定义在函数里面,它在一个叫做"局部作用域"的区域里面。"局部作用域"会在函数被调用的时候创建,而在函数运行结束的时候关闭(并且里面创建的变量跟函数也会被删掉--垃圾回收机制)。
3、通过上面的说法:我们就知道了,第一个例子能实现累加,是因为 i 一直储存在全局作用域,没有被删掉。第二个例子,我们调用了函数,然后创建了局部作用域->定义了 i->函数运行结束后->局部作用域关闭了,i 也被删除了。然后我们再点击, 又重新创建了局部作用域,重新定义 i 。(我们点击是在不停重新创建 i)
---------------------------------------------------------
问题:有没有办法让“局部作用域”不关掉呢? ------------- 那就是"闭包"了。
第三个例子:简单的闭包
我们来分析为什么局部作用域没有被关闭:
①我们在函数内部定义了 i
②定义了函数 add2(),并且在add2()引用了 i
③最后return add2。
④(要注意的是:这里document.onclick=add1(); 并不是调用add1函数[调用是不加括号],而是让add1()执行了,获取到了add1() 的值,我们return add2函数)。其实相当于 documen.onclick = add2 //为了方便理解,我们假设它存在 ;
⑤ 这时就会发现,我们在全局环境中使用在add1函数里面定义的add2函数。
⑥ 因为documen.onclick = add2;的存在,既是作用域链的存在。只要浏览器不被关闭,全局作用域对add2的依赖就会一直存在,而add2的执行依赖add1()里面定义的 i,使得add1()也不会被关闭,i 也不会被重新定义,累加的值也被成功的保存下来。
第四个例子:简写闭包
第五个例子:闭包的作用。
第五个例子:有蛮多初学者说,都听别人闭包好用,可是不知道他的实际应用。像第五个例子,我在全局也定义了一个 i ,也对它进行了控制台输出,发现我们闭包里的函数并不会对全局造成影响,却实现了全局的效果。对于比较大型的合作项目,很多人分工合作,如果每个人都在全局定义变量 ,如果定义了同样名字的变量,对这两个人的程序都会造成一些影响。 这就是闭包。
闭包的用处还很多,明白了原理,你可以继续挖掘它。
还有点需要注意的是:闭包的存在会使得他不会被垃圾回收机制回收,他会比其他函数占更多的内存,过渡使用闭包可能会导致内存占用过多。可能会导致浏览器崩溃的问题。解决方法就是已经达到我们的目的的时候,解除对匿名函数的引用,没有了引用变成了普通函数,被垃圾回收机制回收。
下面我通过五个简单例子,解释闭包原理。
第一个例子
<script> var i = 0; document.onclick = add; function add(){ i++; document.title =i; }; </script>第一个例子都能看懂,是个简简单单的实现 i 累加。无需多说,我们继续看第二个例子。
第二个例子
<script> document.onclick = add; function add(){ var i = 0; i++; document.title =i; }; </script>
第二个例子:将i定义在函数内部,会发现 i 这时候无法实现累加,一直显示是1。这是为什么?
---------------------------------------------------------
原因是:
1、第一个例子的 i 定义在函数外面,它在一个叫做"全局作用域"的区域里面。"全局作用域"只会在浏览器窗口关闭或页面刷新的时候进行关闭。(我们跟第二个例子对比下就知道全局作用域)。
2、第二个例子的 i 定义在函数里面,它在一个叫做"局部作用域"的区域里面。"局部作用域"会在函数被调用的时候创建,而在函数运行结束的时候关闭(并且里面创建的变量跟函数也会被删掉--垃圾回收机制)。
3、通过上面的说法:我们就知道了,第一个例子能实现累加,是因为 i 一直储存在全局作用域,没有被删掉。第二个例子,我们调用了函数,然后创建了局部作用域->定义了 i->函数运行结束后->局部作用域关闭了,i 也被删除了。然后我们再点击, 又重新创建了局部作用域,重新定义 i 。(我们点击是在不停重新创建 i)
---------------------------------------------------------
问题:有没有办法让“局部作用域”不关掉呢? ------------- 那就是"闭包"了。
第三个例子:简单的闭包
<script> document.onclick =add1(); function add1(){ var i = 0; function add2() { i++; document.title =i; } return add2; //运行add1()的获得的值是add2 } </script>第三个例子: 这次还是将 i 定义到函数里面,但我们会发现,i 实现了累加。 这说明我们已经让局部作用域不关闭了,这就是简单的闭包。
我们来分析为什么局部作用域没有被关闭:
①我们在函数内部定义了 i
②定义了函数 add2(),并且在add2()引用了 i
③最后return add2。
④(要注意的是:这里document.onclick=add1(); 并不是调用add1函数[调用是不加括号],而是让add1()执行了,获取到了add1() 的值,我们return add2函数)。其实相当于 documen.onclick = add2 //为了方便理解,我们假设它存在 ;
⑤ 这时就会发现,我们在全局环境中使用在add1函数里面定义的add2函数。
⑥ 因为documen.onclick = add2;的存在,既是作用域链的存在。只要浏览器不被关闭,全局作用域对add2的依赖就会一直存在,而add2的执行依赖add1()里面定义的 i,使得add1()也不会被关闭,i 也不会被重新定义,累加的值也被成功的保存下来。
第四个例子:简写闭包
<script> document.onclick =(function(){ //匿名函数自执行 var i = 0; return function() { //返回另一个匿名函数 i++; document.title =i; } })(); </script>第四个例子:这里涉及到“匿名函数自执行”。(function(){})(); 一般执行函数是在函数名后面加括号,这里(function(){})相当于一个表达式,我们在它后面加(); 。就相当于执行了这个函数。 同样的,我们 return function(){}; 。 也是把这个函数返回出去了,只不过返回出去一个匿名函数。
第五个例子:闭包的作用。
<script> var i = 10 ; document.onclick =(function(){ var i = 0; return function() { i++; document.title =i; } })(); console.log(i); </script>
第五个例子:有蛮多初学者说,都听别人闭包好用,可是不知道他的实际应用。像第五个例子,我在全局也定义了一个 i ,也对它进行了控制台输出,发现我们闭包里的函数并不会对全局造成影响,却实现了全局的效果。对于比较大型的合作项目,很多人分工合作,如果每个人都在全局定义变量 ,如果定义了同样名字的变量,对这两个人的程序都会造成一些影响。 这就是闭包。
闭包的用处还很多,明白了原理,你可以继续挖掘它。
还有点需要注意的是:闭包的存在会使得他不会被垃圾回收机制回收,他会比其他函数占更多的内存,过渡使用闭包可能会导致内存占用过多。可能会导致浏览器崩溃的问题。解决方法就是已经达到我们的目的的时候,解除对匿名函数的引用,没有了引用变成了普通函数,被垃圾回收机制回收。
相关文章推荐
- 一个简单的例子教你明白XMLHTTPRequest的原理
- Thread学习(七) 用读写锁ReadWriteMethod实现个简单的例子,cache缓存的原理
- 关于缓冲区溢出攻击原理的简单例子(C语言编写)
- 一个闭包的简单例子
- js中闭包原理谈和原型及例子
- 一个简单的例子看明白如何利用window.location.hash实现ajax操作时浏览器的前进/后退功能
- 一个简单的小例子让你明白c#中的委托-终于懂了!
- 【unity3d游戏开发之基础篇】unity3d射线的原理用法以及一个利用射线实现简单拾取的小例子
- unity3d射线的原理用法以及一个利用射线实现简单拾取的小例子
- 简单的感知学习原理例子 人工神经网络 Perceptron Learning Rule
- 【unity3d游戏开发之基础篇】unity3d射线的原理用法以及一个利用射线实现简单拾取的小例子
- AAA Spring AOP原理及拦截器(aop配置最简单例子)
- Unity3d射线的原理用法以及一个利用射线实现简单拾取的小例子
- 面向对象编程设计模式--简单工厂模式讲解(历史上最简单明白的例子)
- Lucene 4.X 倒排索引原理与实现: (3) Term Dictionary和Index文件 (FST详细解析)——直接看例子就明白了!!!
- 学习javascript的闭包特性用C#来实现一个简单的例子
- 一个简单的python闭包例子
- 简单例子,快速学习sort函数——五个数求最大数和最小数
- PHP匿名函数 闭包简单例子
- 【unity3d游戏开发之基础篇】unity3d射线的原理用法以及一个利用射线实现简单拾取的小例子