<body> <button>测试1</button> <button>测试2</button> <button>测试3</button> <!-- 需求: 点击某个按钮, 提示"点击的是第n个按钮" --> <script type="text/javascript"> var btns = document.getElementsByTagName('button') /* //有问题 for(var i=0,length=btns.length;i<length;i++) { var btn = btns[i] btn.onclick = function () { alert('第'+(i+1)+'个') } }*/ //解决一: 保存下标 /*for(var i=0,length=btns.length;i<length;i++) { var btn = btns[i] btn.index = i btn.onclick = function () { alert('第'+(this.index+1)+'个') } }*/ //解决办法: 利用闭包 for(var i=0,length=btns.length;i<length;i++) { (function (i) { var btn = btns[i] btn.onclick = function () { alert('第'+(i+1)+'个') } })(i) } </script> </body>
闭包
// 最简单的闭包 function A(){ function B(){ console.log("Hello Closure!"); } return B; } var c = A(); c();//Hello Closure! // 解释 (1)定义了一个普通函数A (2)在A中定义了普通函数B (3)在A中返回B(确切的讲,在A中返回B的引用) (4)执行A(),把A的返回结果赋值给变量c (5)执行c()
// javascript中的GC机制:在javascript中,如果一个对象不再被引用,那么这个对象就会被GC回收,否则这个对象一直会保存在内存中。
// B定义在A中,因此B依赖于A,而外部变量c又引用了B,所以A间接的被c引用,也就是说,A不会被GC回收,会一直保存在内存中
// 详细查看: https://www.mybj123.com/339.html
// 经典题目 for (var i = 1; i <= 5; i++) { setTimeout(function timer() { console.log(i); }, 1000); } } // 输出 6 6 6 6 6 setTimeout是异步的,需要等for循环里面的执行完成才会执行,等i=5的时候,i++,这个时候i就变成了6 方法一:使用闭包 for (var i = 1; i <= 5; i++) { (function(i) { setTimeout(function timer() { console.log(i); }, 1000); })(i) } // 输出 1 2 3 4 5 方法二:var改为let for (let i = 1; i <= 5; i++) { setTimeout(function timer() { console.log(i); }, 1000); } } // 输出 1 2 3 4 5
<!-- 1. 如何产生闭包? * 当一个嵌套的内部(子)函数引用了嵌套的外部(父)函数的变量(函数)时, 就产生了闭包 2. 闭包到底是什么? * 使用chrome调试查看 * 理解一: 闭包是嵌套的内部函数(绝大部分人) * 理解二: 包含被引用变量(函数)的对象(极少数人) * 注意: 闭包存在于嵌套的内部函数中 3. 产生闭包的条件? * 函数嵌套 * 内部函数引用了外部函数的数据(变量/函数) --> <script type="text/javascript"> function fn1 () { var a = 3 function fn2 () { console.log(a) } } fn1() </script>
常见的闭包
<!-- 1. 将函数作为另一个函数的返回值 2. 将函数作为实参传递给另一个函数调用 --> <script type="text/javascript"> // 1. 将函数作为另一个函数的返回值 function fn1() { var a = 2 function fn2() { a++ console.log(a) } return fn2 } var f = fn1() f() // 3 f() // 4 // 2. 将函数作为实参传递给另一个函数调用 function showMsgDelay(msg, time) { setTimeout(function () { console.log(msg) }, time) } showMsgDelay('hello', 1000) //hello </script>
闭包的作用 , 生命周期
<!-- 1. 使用函数内部的变量在函数执行完后, 仍然存活在内存中(延长了局部变量的生命周期) 2. 让函数外部可以操作(读写)到函数内部的数据(变量/函数) 问题: 1. 函数执行完后, 函数内部声明的局部变量是否还存在? 2. 在函数外部能直接访问函数内部的局部变量吗? --> <script type="text/javascript"> function fun1() { var a = 3; function fun2() { a++; //引用外部函数的变量--->产生闭包 console.log(a); } return fun2; } var f = fun1(); //由于f引用着内部的函数-->内部函数以及闭包都没有成为垃圾对象 f(); //4 //间接操作了函数内部的局部变量 f(); //5
f = null //此时闭包对象死亡
</script>
闭包的应用_自定义js模块
/** * 自定义模块1 */ function coolModule() { //私有的数据 var msg = 'atguigu' var names = ['I', 'Love', 'you'] //私有的操作数据的函数 function doSomething() { console.log(msg.toUpperCase()) } function doOtherthing() { console.log(names.join(' ')) } //向外暴露包含多个方法的对象 return { doSomething: doSomething, doOtherthing: doOtherthing } }
<!-- 闭包的应用2 : 定义JS模块 * 具有特定功能的js文件 * 将所有的数据和功能都封装在一个函数内部(私有的) * 只向外暴露一个包信n个方法的对象或函数 * 模块的使用者, 只需要通过模块暴露的对象调用方法来实现对应的功能 --> <script type="text/javascript" src="05_coolModule.js"></script> <script type="text/javascript"> var module = coolModule() module.doSomething() module.doOtherthing() </script>
/** * 自定义模块2 */ (function (window) { //私有的数据 var msg = 'atguigu' var names = ['I', 'Love', 'you'] //操作数据的函数 function a() { console.log(msg.toUpperCase()) } function b() { console.log(names.join(' ')) } window.coolModule2 = { doSomething: a, doOtherthing: b } })(window)
<!-- 闭包的应用2 : 定义JS模块 * 具有特定功能的js文件 * 将所有的数据和功能都封装在一个函数内部(私有的) * 只向外暴露一个包信n个方法的对象或函数 * 模块的使用者, 只需要通过模块暴露的对象调用方法来实现对应的功能 --> <script type="text/javascript" src="05_coolModule2.js"></script> <script type="text/javascript"> coolModule2.doSomething() coolModule2.doOtherthing() </script>
闭包的缺点及解决
<!-- 1. 缺点 * 函数执行完后, 函数内的局部变量没有释放, 占用内存时间会变长 * 容易造成内存泄露 2. 解决 * 能不用闭包就不用 * 及时释放 --> <script type="text/javascript"> function fn1() { var a = 2; function fn2() { a++; console.log(a); } return fn2; } var f = fn1(); f(); // 3 f(); // 4 f = null // 释放 </script>