2019独角兽企业重金招聘Python工程师标准>>>

本文之前发表过一次,虽然当时也是精心书写过,但还是感觉有些问题本说明白,又走上了"把简单的事说复杂"的老毛病,所以第二次修改希望让看的人,尤其是对于闭包还心有畏惧的TX能有些收获.

    内部函数大营救

闭包的深刻定义留在下面说,我先要说明的是内部函数这个东东.顾名思义,内部函数就是定义在一个函数内部的另一个函数.Javascript的作用域决定了内部函数在外部函数的外面无法直接调用.这就好比一个被恶龙看住的公主,勇士你有办法救她出来吗?

勇士如何斗恶龙?

想要将内部函数从外部函数的作用域中营救出来,通常有2种办法.

第一种就是将内部函数指定给一个全局变量,那么此时内部函数通过把引用保存全局变量中实现了逃脱,但是函数名仍然被截留在外部函数作用域中,就好比公主改头换面,从此和勇士隐姓埋名.

var c ;
function a(){function b(){console.log("b");}c = b;console.log("a");
}a();
c();

第二种就是勇士和恶龙一阵恶斗,最后恶龙不敌将公主送出来,从此勇士和公主过上了没羞没臊的...好像扯远了,这就让外部函数通过return将内部函数弹出,利用"返回值".

var c ;
function a(){function b(){console.log("b");}return b;
}c = a();
c();

这样即使离开函数作用域也能通过引用调用内部函数的事实,意味着只要存在调用这些内部函数的可能,javascript就会保留被引用的函数.在javascript运行时需要跟踪引用这个内部函数的所有变量,直到最后一个变量被废弃,javascript的垃圾收集器才会出面释放对应的内存空间.

    闭包就这样出来了

当内部函数在定义它的作用域外部被引用时,就创建了该内部函数的一个闭包.这时就形成了一个封闭的空间,外部函数的局部变量被赋予了新的力量.从本质上讲如果内部函数引用了外部函数的变量,相当于延长了这个变量的生命周期.外部函数的变量的生命周期与内部闭包联系在了一起.

我比较倾向于闭包算是Javascript作用域的一种特殊运用.在阐述闭包的时候,我们应该首先为它下一个定义,比如说闭包到底是什么?变量?函数?代码的特殊写法?这个概念委实不好定义,之前看到过一个比较好的定义就是这么说的:

闭包是指:在javascript中内部函数总是可以访问其所在外部函数的变量,即使外部函数被返回(寿命终结)了之后.

我更倾向于闭包是形成一种特定的javascript环境,这样环境的形成一般通过函数内部函数的返回得到的,一个闭包就是一个函数返回时,没有释放资源的栈区.

闭包在什么时候用,或者说什么时候我们会需要闭包?比较明显或者说比较基础的说法是在需要得到函数内部变量的时候,我们就可以使用闭包.上面提到了闭包构建了一个没有释放资源的栈区,所以说,闭包可以留住一些原本留不住的东西.函数内部的局部变量本来使用完就用回收释放掉,但是通过闭包可以临时将他们保存起来.而且不会污染全局变量的空间.

先上一段代码,用一用闭包.

var a = [1,2,3,4];for(var i=0,len=a.length;i<len;i++){var s = a[i];setTimeout(function(){console.log(s);},2000*(i+1));}

开始翻译代码,有一个包含4个数字的数组,遍历它然后每取一个元素就在2秒后输出一下这个元素.理论上结果应该是每间隔2秒输出一个数字,从1到4.可是实际的结果是4,4,4,4.

开始解释这是为什么,首先第一次循环取出1后,执行setTimeout(),然后又开始执行第二次for循环.这时问题出来了,在第二次for循环s=2的时候,第一次的输出s=1的代码还没有执行,s就已经被覆盖了.因为setTimeout()留不住前一刻的s变量的值.一旦s改变了,它就只能输出最新的s.

现在加入闭包,也就是形成一个函数有函数的环境,怎么说呢,因为setTimeout没有能力保存住每一次s变量的值,所以人为的给它建立一个不会释放掉s资源的这么一个环境,形成闭包后,s的值就被保存在每一个闭包环境中,各自输出即可.

var a = [1,2,3,4];for(var i=0,len=a.length;i<len;i++){var s = a[i];(function(x){setTimeout(function(){console.log(x);},1000*(i+1));})(s);}for(var i=0,len=a.length;i<len;i++){var s = a[i];var y = function(x){setTimeout(function(){console.log(x);},1000*(i+1));}(s);}

上面代码片段中的两种写法都可以,前一个是匿名函数的自执行构成闭包,后一个是通过一个y变量取一个函数的返回.它们都是将s作为实参,然后在闭包中用形参x保存,然后继续执行,这样保证x在其中没有被释放,可以等到全部执行完,通过javascript进行垃圾回收.这就是最简单的闭包的例子.

再看几个代码片段,每一个都用到了闭包,看看它们和没有加闭包有什么不一样吧.

var a = (function(){var x = 0;return function(){console.log(x);x++;}})();a();//0a();//1a();//2//实际输出的是x的值,但是如果你在浏览器监听x会发现它不是全局变量,所以var x = 0看起来只执行了一次,是不是很奇怪~
var name = "The Window";
var object = {name : "My Object",getNameFunc : function(){return function(){return this.name;};}
};
alert(object.getNameFunc()());//输出是The window,obj.getNameFunc()执行到这里取出的是一个匿名函数function(){return this.name},最后一个()来执行这个匿名函数,this这时指向的是全局的window.return function(){}这样的代码,返回的是方法体.

看到这里要提出一个问题,大家有没有发现这些闭包的应用都会出现return.而且基本上都是return一个function,按照我的理解这样返回一个方法体或者说匿名函数,return切断了方法体的原有上下文,将它返回到一个新的上下文环境中.同时函数本身有自己的上下文环境或者说作用域,在javascript中只有函数拥有自己独立的作用域结构,所以闭包是依赖函数的.

再来看几个经典的代码,为了加深理解,个人感觉对于闭包的理解还是要多看代码.

function counter(s){var count = s;return {increment:function(){count++;},get:function(){return count;}};}var c = counter(99);c.increment();console.log(c.get());//首先c是什么?是一个对象.里面有increment和get两个方法.同时传入参数99,这时increment方法所在的对象返回了,理论上应该脱离之前counter的作用域了.但是因为increment是一个函数,形成闭包还维持着对count变量的引用,所以还能访问到变量count

对于闭包,其实我们日常应用中会经常遇到,往大的方向上将所有的代码都是在一个大的闭包中完成的.把闭包看作一个思想或者技巧,它与作用域以及内存的联系很紧密,相互有很多可以印证的东西. 我个人看闭包应用最好的就是jQuery中的很多方法,都应用了闭包.希望本文能够给你带来帮助~

转载于:https://my.oschina.net/blogshi/blog/192022

勇士斗恶龙:没那么复杂的Js闭包(改)相关推荐

  1. AS 3学习书上的例子,勇士斗恶龙

    放在第一帧测试: import flash.utils.Timer; import flash.events.TimerEvent; //创建英雄 var hero:Object=new Object ...

  2. 我的创业项目steam游戏王子斗恶龙(含技术透露)

    这是一个冒险类RPG游戏,王子在大陆冒险,降妖除魔,可以使用咒文,道具,还能买装备,剧情是很好的.是王子拯救世界的故事,通过不断变强,打倒最终Boss.我很喜欢这部游戏,希望大家喜欢,这是我做的.我是 ...

  3. 前端面试题 HTML5 CSS3(盒子模型、盒子水平垂直居中、经典布局) JS(闭包、深浅克隆、数据劫持和拦截) 算法(排序、去重、数组扁平化) Vue(双向数据绑定原理、通信方式)

    前端面试题 HTML5 相关面试题 CSS3 相关面试题 盒子模型 盒子水平垂直居中的方案 经典布局方案 圣杯布局 双飞翼布局 flex布局 定位方式布局 css实现三角形 JS 相关面试题 8种数据 ...

  4. JS闭包的理解及常见应用场景

    JS闭包的理解及常见应用场景 一.总结 一句话总结: 闭包是指有权访问另一个函数作用域中的变量的函数 1.如何从外部读取函数内部的变量,为什么? 闭包:f2可以读取f1中的变量,只要把f2作为返回值, ...

  5. 简单理解js闭包、类型引用....第一章

    js 闭包函数.类型引用.this指向.对象原型链...这些东西让我们对js又爱又恨!js虐我千百遍,我待js如初恋. 很多初学者一开始会觉得这些概念没什么用,导致对这些东西产生一种抵抗力.接下来我们 ...

  6. js 闭包作用域和作用域链_Java:伪造工厂的闭包以创建域对象

    js 闭包作用域和作用域链 最近,我们想创建一个域对象,该对象需要具有外部依赖关系才能进行计算,并且希望能够在测试中解决该依赖关系. 最初,我们只是在领域类中引入依赖关系,但这使得无法在测试中控制其值 ...

  7. js 闭包函数 构造函数_JavaScript中的闭包,库里函数和酷抽象

    js 闭包函数 构造函数 In this article, we will talk about closures and curried functions and we'll play aroun ...

  8. 详解之-js闭包的用途

    js闭包可以用在许多地方.它的最大用处有两个,一个是前面提到的可以读取函数内部的变量,另一个就是让这些变量的值始终保持在内存中.具体怎么理解呢,各位看官请仔细看好下文 我们来看看闭包的用途.事实上,通 ...

  9. 面试官:谈谈对JS闭包的理解及常见应用场景(闭包的作用)

    文章目录 对JS闭包的理解及常见应用场景(闭包的作用) 1.变量作用域 2.如何从外部读取函数内部的变量? 3.闭包概念 4.闭包用途 5.闭包的理解 6.闭包应用场景 setTimeout传参 回调 ...

最新文章

  1. AI独角兽面对BAT,挑战还是臣服?| 《财经》封面
  2. 带你和Python与R一起玩转数据科学: 探索性数据分析(附代码)
  3. 如何在ubuntu下使用samba创建共享
  4. xmlns=http://schemas.xmlsoap.org/wsdl/,这是什么意思,我只知道:xmlns:xx=....,
  5. 剑指Offer面试题:2.二维数组中的查找
  6. 高并发之并发容器详解(从入门到超神)
  7. python字符串去头尾_带你认识优秀的python代码
  8. Excel VBA利用事件对图表自动更新
  9. 浅谈oracle中for update 和 for update nowait 和 for update wait x的区别
  10. Crnn中文end-to-end识别
  11. aic值检验 p值_23. 假设检验的时候为什么常写p lt; 0.05,而不写具体的p值?
  12. Matlab 终止正在运行的程序
  13. Hive教程(01)- 初识Hive
  14. Linux驱动开发-编写FT5X06触摸屏驱动
  15. matlab opnet,opnet环境变量和matlab联调心得
  16. 中国出海50强,华为超越阿里得亚军,第一名居然是它?
  17. 机器学习实战(入门级) ------ Kaggle 泰坦尼克号幸存者预测 (随机森林,KNN,SVM)
  18. 如何解决笔记本键盘某一个键一直在自动按下
  19. 实现求出100~200之间的全部素数,每行输出8个数,每个数宽度为5列。 输入格式:无 输出格式:“%5d“ “\n“
  20. Android入门知识全套笔记

热门文章

  1. 2018帮助_字节跳动扶贫获“北京市扶贫协作奖”,一年帮助8万贫困人口增收
  2. Java基础看jvm,JAVA基础知识|java虚拟机(JVM)
  3. Paddle中的数据集合定义与加载
  4. 节能电磁无线电导航信号放大电路 150kHz制版
  5. 全国大学生智能汽车竞赛介绍-2020
  6. 2019全国普通高校学科竞赛排行榜发布
  7. c语言排班系统设计报告,C语言课程设计关于排班系统的一些问题
  8. c++重定向后恢复_【STM32CubeIDE】重定向printf
  9. centos linux引导修复_CentOS没了,Linux的新世界来了
  10. eclipse 右键项目为什么没有properties菜单_只需几步,从零开始搭建SSM项目