渡一—— 9-3 闭包-经典版
//里面有形参,实参,匿名函数,闭包等概念的整理;
1.原始版
1 2 3 4 5 6 7 8 9 10 11 12 13 | function createFunctions(){ var result = new Array(); for ( var i=0;i<10;i++){ result[i] = function (){ // lv 3 return i }; } return result; } var funcs = createFunctions(); for ( var i=0;i<funcs.length;i++){ document.write(funcs[i]() + "<br/>" ); } |
//这里执行createFunctions()方法时,会执行完里面的for循环,所以当i退出时i=10;一共调用了10次;
//output: 10 10 10 10 ...10(10个10)
2.改进版
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | function createFunctions(){ var result = new Array(); for ( var i=0;i<10;i++){ result[i] = function (num){ // lv 2 return function (){ // lv 3 return num //这里的num是闭包变量,因为他用的是外面function传入的num值,其它地方并没有定义过; } }(i); } return result; } var funcs = createFunctions(); for ( var i=0;i<funcs.length;i++){ document.write(funcs[i]() + "<br/>" ); } //output: 0 1 2 3 ...9(0-9) |
另一种写法(推荐)
1 function test(){ 2 var arr = []; 3 for(var i=0;i<10;i++){ 4 (function(j){ 5 arr[j] = function(){ 6 console.log(j+""); 7 } 8 }(i)) 9 } 10 return arr; 11 } 12 var myArr = test(); 13 for(var j=0;j<10;j++){ 14 myArr[j]();//1 2 3 4 5 ... 15 }
2-2.改进版
function createFunctions(){ var result = new Array(); for(var i=0;i<10;i++){ result[i] = function(i){ // lv 3 return i }; } return result; } var funcs = createFunctions(); for(var i=0;i<funcs.length;i++){ document.write(funcs[i](i) + "<br/>"); }
//形参是接受参数;实参是传入参数;
//这里58行(i)是实参;将传入50行的function(i)这里的形参;但如果这里没有形参的话,实参也就没有了意义;
//但如果实参的个数<形参时,形参中缺少的形参值是undefined;
//output: 0 1 2 3 ...9(0-9)
3.总结
1 2 3 4 5 6 7 8 9 | function a() { var i = 0; function b() { alert(++i); } return b; /*注意如果这里没有retrun b;那么调用a()方法时b将不会作为a的一个返回值,这时c=a();c的值就是undefined,也就无法创建闭包;*/ } var c = a(); c(); |
这段代码有两个特点:
1、函数b嵌套在函数a内部;
2、函数a返回函数b。
这样在执行完var c=a()后,变量c实际上是指向了函数b,再执行c()后就会弹出一个窗口显示i的值(第一次为1)。这段代码其实就创建了一个闭包,为什么?因为函数a外的变量c引用了函数a内的函数b,就是说:
当函数a的内部函数b被函数a外的一个变量引用的时候,就创建了一个闭包。
简而言之,闭包的作用就是在a执行完并返回后,闭包使得Javascript的垃圾回收机制GC不会收回a所占用的资源,因为a的内部函数b的执行需要依赖a中的变量。这是对闭包作用的非常直白的描述,不专业也不严谨,但大概意思就是这样,理解闭包需要循序渐进的过程。
在上面的例子中,由于闭包的存在使得函数a返回后,a中的i始终存在,这样每次执行c(),i都是自加1后alert出i的值。
那么我们来想象另一种情况,如果a返回的不是函数b,情况就完全不同了。因为a执行完后,b没有被返回给a的外界,只是被a所引用,而此时a也只会被b引用,因此函数a和b互相引用但又不被外界打扰(被外界引用),函数a和b就会被GC回收。
闭包的功能:
/*可以做缓存*/ function test(){ var food = "apple"; var obj = { eat:function(){ if(food != ""){ console.log("I am eating" + food); food=""; }else{ console.log("there is nothing!empty!") } }, push:function(myFood){ food = myFood; } } return obj; } var person = test(); person.eat(); person.eat(); person.push('banana'); person.eat();
/*闭包保存变量*/ function a(){ function b(){ var bbb=234; console.log(aaa); } var aaa = 123; return b; } var glob = 100; var demo = a(); demo();
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· 三行代码完成国际化适配,妙~啊~
· .NET Core 中如何实现缓存的预热?