// var one = {"id":1, "leasetime":2, "ney":0,"myhuifangshi":0} // var fe=0; //
顺晟科技
2021-06-16 10:57:52
147
在计算机科学中,闭包是在包含一个或多个绑定变量的环境中进行计算的函数。调用时,函数可以访问这些变量。
闭包是一个函数,它“记住它周围发生的事情”。它表明“一个功能”的主体中定义了“另一个功能”
一个“闭包”是一个表达式(通常是一个函数),它有一个自由变量和一个这些变量绑定的环境(环境“关闭”了表达式)。闭包是一个内部函数,它关闭外部函数范围内的变量。然而,如果外部函数不返回这个内部函数,闭包的特性就不能被揭示。如果一个外部函数返回这个内部函数,返回的内部函数就变成了一个名副其实的闭包。这时闭包封闭的外部变量就是自由变量,而且因为自由变量的存在,即使外部函数返回,它占用的内存也不会被释放。)
闭包是可以读取其他函数内部变量的函数。
闭包是可以访问另一个函数范围内的变量的函数。
闭包是javascript中的一个难点,很多应用都是靠闭包来实现的。要理解闭包,首先要理解变分原理的范围。参见Javascript变量作用域。你不用仔细理解前面关于闭包的定义。可以先往下看,看完再回头看前面的定义,有助于理解闭包。让我们首先看下面的例子:
function outer(){ var I=100;function inner(){ console . log(I);}}
以上代码,根据变量的范围,函数外的所有局部变量对函数内的都是可见的;函数内部的局部变量在函数内部之外是不可见的,所以不可能读取函数内部之外的局部变量。
由于函数内部可以读取函数外部的局部变量,所以只要内部作为返回值,内部的局部变量就可以直接在外部读取。
function outer(){ var I=100;function inner(){ console . log(I);} return inner} var RS=outer();RS();
该功能有两个特征:
函数内部嵌套在函数外部;
函数外部返回函数内部。
这样,在执行var rs=outer()之后,实际的rs指向函数inner。这段代码实际上是一个闭包。也就是说,当函数外内部的函数被函数外外部的变量引用时,就创建了闭包。
function outer(){ var I=100;function inner(){ console . log(I);} return inner} var RS=outer();RS();//100 RS();//101 RS();//102
在上面的代码中,rs是闭包内部函数。Rs已经运行了三次,次100,第二次101,第三次102,说明函数outer中的局部变量I一直保存在内存中,不调用自动清零。
闭包的作用是在执行并返回外部函数后,闭包阻止了javascript的grabage收集机制回收外部函数占用的内存,因为外部函数的内部函数inner的执行依赖于外部函数中的变量。(另一种解释:outer是inner的父函数,赋给一个全局变量,这样inner就会一直在内存中,inner的存在依赖于outer,outer会一直在内存中,调用后不会被垃圾收集。).
闭包可以访问函数内部的所有变量。
当函数返回闭包时,函数的作用域将保留在内存中,直到闭包不存在。
由于作用域链的机制,闭包只能得到函数中任意变量的最后一个值。请看下面的例子:
函数f(){ var RS=[];for(var I=0;i 10I){ RS[I]=function(){ return I;};}返回RS;} var fn=f();for(var I=0;i fn.lengthI) {console.log('函数fn[' i ']()返回值: ' fn[I]());}
该函数将返回一个数组。从表面上看,似乎每个函数都应该返回自己的索引值。实际上,每个函数返回10,因为函数f的活动对象存储在个函数的作用域链中,它们都引用同一个变量I,当函数f返回时,变量I的值为10,然后每个函数持有变量I的同一个变量对象,我们可以通过创建另一个匿名函数来强制闭包按预期行为。
函数f(){ var RS=[];for(var I=0;i 10I){ RS[I]=function(num){ return function(){ return num;};}(I);}返回RS;} var fn=f();for(var I=0;i fn.lengthI) {console.log('函数fn[' i ']()返回值: ' fn[I]());}
在这个版本中,我们没有直接将闭包赋给数组,而是定义了一个匿名函数,并将执行匿名函数的结果立即赋给数组。这里,匿名函数有一个参数num。当调用每个函数时,我们传入变量I。由于参数是通过值传递的,变量I将被复制到参数num。在这个匿名函数中,创建并返回一个用于访问num的闭包,这样rs数组中的每个函数都有自己num变量的副本,因此它可以返回不同的值。
var name=' Jackvar o={ name : ' bingdian ',GetName : function(){ return function(){ return this . name;};} } console . log(o . GetName()();//杰克瓦尔名字='杰克';var o={ name : ' bingdian ',GetName : function(){ var self=this;return function(){ return self . name;};} } console . log(o . GetName()();//兵点
function assignanhandler(){ var El=document . GetElementbyID(' demo ');El . onclick=function(){ console . log(El . id);} } AssignHandler();
上面的代码创建了一个闭包作为el元素事件处理程序,这个闭包创建了一个循环引用。只要匿名函数存在,el的引用号至少为1,因此它占用的内存永远不会被回收。
function assignanhandler(){ var El=document . GetElementbyID(' demo ');var id=el.idEl . onclick=function(){ console . log(id);} el=null} AssignHandler();
将变量el设置为null可以取消对DOM对象的引用,保证其占用内存的正常恢复。
任何一对花括号({and})中的语句集都属于一个块,其中定义的所有变量在代码块之外都是不可见的,这称为块级作用域。
(function(){ //块级作用域})();
保护函数中的变量。和前面的例子一样,函数外层的I只能被函数内层访问,不能被其他方式访问,从而保护了I的安全性。
在内存中维护一个变量。和前面的例子一样,因为闭包,函数outer中的I总是存在于内存中,所以每次执行rs()的时候,I都会增加1。
15
2022-09
15
2022-09
15
2022-09
31
2021-07
04
2021-07
04
2021-07