一、选定知识点:闭包
二、指令学习
1. 闭包MDN的定义
闭包(closure)是一个函数以及其捆绑的周边环境状态(lexical environment,词法环境)的引用的组合。换而言之,闭包让开发者可以从内部函数访问外部函数的作用域。在 JavaScript 中,闭包会随着函数的创建而被同时创建。
三、做练习题 、归纳比较、测试新题
1. 通过立即执行函数和返回函数实现闭包
let data = []
for(let i = 0; i < 3; i++) {
data[i] = (function (i) {
return function () {
console.log(i)
}
})(i)
}
data[0]()
data[1]()
data[2]()
// 0
// 1
// 2
2. 通过返回对象,调用对象方法,返回函数递归调用外部函数实现闭包
function fun (n, o) {
console.log(o)
return {
fun: function (m) {
return fun(m,n)
}
}
}
let a = fun(0)
a.fun(1)
步骤分析:
1. 传递参数 n =0 ,o 没有传递为undefined
2. 打印undefined
3. 返回一个对象给a
4. a,fun(1) , 传递参数m =1
5. 执行fun(m, n) ,当内部函数参数没有某个变量时,往外部函数查找,外部函数的参数 n =0
6. 执行fun(m,n) = fun(1, 0)
7. 打印0
归纳对比,在练习题1和练习题2中有哪些共性和差异性
1.共性
1-1 都有两个函数,一个外部函数和一个内部函数
1-2 内部函数都会调用外部函数的参数
1-3 外部函数的参数值因为内部函数一直引用,所以参数的内存地址没有被释放掉
2. 差异性
2-1 实现闭包的方式不同
①中通过立即执行函数和函数的返回值,调用返回的函数,从而实现闭包
②中通过外部函数的返回值,返回一个对象,通过调用这个对象的fun函数 的返回函数,递归调用外部函数,从而实现闭包
2-2 调用方法的次数不同
① 通过调用一次外部函数,内部函数自动执行,调用一次
② 先调用一次外部函数,再根据外部函数的返回值,手动再调用一次内部函数,调用两次
2-3 返回值不同,调用方式不同
① 返回函数是立即自动执行的
② 返回对象,对象下的方法需要手动调用
3. 通过倒计时定时器方法接收外部函数的变量,实现闭包
function fn1 () {
for (var i =0 ; i< 4; i++) {
var tc = setTimeout(function (i) {
console.log('索引',i)
console.log('定时器的返回值',tc)
},10, i)
}
}
fn1()
// 索引 0
// 定时器的返回值 4
// 索引 1
// 定时器的返回值 4
// 索引 2
// 定时器的返回值 4
// 索引 3
// 定时器的返回值 4
归纳对比,在练习题2和练习题3中有哪些共性和差异性
1. 共性
1-1 都有两个函数,一个外部函数和一个内部函数
1-2 内部函数都调用了外部函数的变量,变量包括外部作用域内的变量和参数
2.差异性
2-1 使用外部参数的方式不同
②中通过作用域往上找到对应的参数,然后使用
③中通过定时器,传递实参,设置形参,传递给内部函数使用
4. 通过循环定时器,接收外部函数的变量,实现闭包
function fn2 () {
for (var i =0; i < 4; i++) {
var tc = setInterval(function(i,tc){
console.log('索引',i)
clearInterval(tc)
},10,i,tc)
if (i=== 3) {
setTimeout(function (tc){
clearInterval(tc)
},10,tc)
}
}
}
fn2()
// 0
// 1
// 2
// 3 一直循环
PS: 因为先走定时器,再赋值给tc,所以每次清除定时器其实清除掉是上一次的定时器,所以最后一次定时器没有清除。
通过i===3给任务队列加一个清除的定时器