01 什么是闭包
闭包指有权访问另一个函数作用域中变量的函数
其实,闭包就是一个内部函数
1.举例
function outer() {
let a = 5 // outer中的变量
function inner() {
console.log(a) //5
}
inner()
}
outer()
//a是outer中的变量, inner函数的作用域访问了另一个函数即outer内部的变量 a
2.什么是闭包函数
函数inner就是一个闭包函数
function outer(){
function inner(){
}
}
02闭包的三个可访问作用域
1、在它自身声明之内声明的变量
function outer() {
function inner() {
let a = 5 // 自身
console.log(a) // 5
}
inner()
}
outer()
当闭包函数inner被调用的时候,控制台会输出5
闭包函数可以访问所有在其声明内部声明的变量
2、对全部变量的访问
let b = 'global' // 全局变量
function outer() {
function inner() {
let a = 5
console.log(b) // global
}
inner()
}
outer()
闭包能访问全局变量,此时调用闭包函数inner时,控制台会输出global
3、访问外部函数的变量
let b = 'global'
function outer() {
let c = 'out' // 外部变量
function inner() {
let a = 5
console.log(c) // out
}
inner()
}
outer()
inner函数能访问到外部函数(outer)中的变量c
03 闭包能记住它的上下文
let outerFn = (arg) => {
let outer = "outer"
let innerFn = () => {
console.log(outer) // out
console.log(arg) // 5
}
return innerFn
}
outerFn(5)()
当outerFn(5)被调用时,返回了innerFn 函数
当innerFn 被返回,JavaScript引擎视innerFn为一个闭包,并相应的设置了它的作用域;arg和outer被设置到inner的作用域层级中,返回函数的引用存储到innerFn 中;
innerFn被调用时即(outerFn(5)())就记住了arg和outer
04 在浏览器中查看是否有闭包
图片
在浏览器中F12查看,closure就是闭包的意思
05 闭包的案例
1.点击每个li能打印出每个li的索引
<body>
<ul class="nav">
<li>语文</li>
<li>数学</li>
<li>英语</li>
<li>化学</li>
</ul>
</body>
<script>
// 创建4个立即执行函数
var lis = document.querySelector('.nav').querySelectorAll('li')
for (var i = 0; i < lis.length; i++) {
(
function (i) {
lis[i].onclick = function () {
console.log(i)
}
}
)(i)
}
// 立即循环函数传入的是当前循环中的i值
</script>
2. 3秒后,打印所有li的索引
<body>
<ul class="nav">
<li>语文</li>
<li>数学</li>
<li>英语</li>
<li>化学</li>
</ul>
</body>
<script>
// 闭包应用3秒后,打印所有li的索引
var lis = document.querySelector('.nav').querySelectorAll('li');
for (var i = 0; i < lis.length; i++) {
(function (i) {
setTimeout(function () {
console.log(i);
}, 3000)
})(i);
}
</script>
06 闭包的经典案例题
1、案例题1
<script>
var name = "The Window";
var object = {
name: "My Object",
getNameFunc: function () {
return function () {
return this.name;
};
}
};
console.log(object.getNameFunc()()) // The Window
</script>
分析 拆解
object.getNameFunc() // 相当于
var f = object.getNameFunc()
f = function () {
return this.name;
};
object.getNameFunc()() // 相当于
f()
this 在匿名函数里 就是f() 此时指向window
2、案例题2
<script>
var name = "The Window";
var object = {
name: "My Object",
getNameFunc: function () {
var that = this;
return function () {
return that.name;
};
}
};
console.log(object.getNameFunc()()) // My Object
</script>
分析 拆解
object.getNameFunc() // 相当于
var f = function () {
return that.name;
};
object.getNameFunc()() // 相当于
f()
var that = this的this是getNameFunc函数的调用者
object.getNameFunc()调用了getNameFunc 即this指向 object
f()再调用的时候,that存储的是object中的name
07 闭包的作用
1.延伸了变量的作用范围(可以读取函数内部的变量)
function outer() {
let a = 5
function inner() {
console.log(a) //5
}
return inner
}
let f = outer()
f()
全部作用域f()也能访问局部作用域的变量a
2.让变量的值始终保持在内存中
<script>
function outer(){
var i = 0;
function inner(){
i++
console.log(i)
}
return inner
}
var f = outer()
f() // 1
f() // 2
</script>
理论上,局部变量在函数运行完是消失的,但是再次调用fn,i的值是2,说明变量保存在f这个对象上
下一篇:【this问题】 JS中改变函数内部this的指向问题
推荐阅读:
1、异步编程解决方案async/await
2、异步编程解决方案promise