一、闭包的概念:
能够访问另一个函数的变量,和储存数据的函数。
在之前我们学到,javaScript作用域分为局部作用域和全局作用域;
基于我们所熟悉的作用域链相关知识,我们知道在js作用域环境中,访问变量的权利是由内向外。
内层作用域可以访问当前作用域下的变量,并且可以向外访问到包含当前作用于的外层作用域下的变量。
外层作用域可以访问当前作用域下的变量,但是不可访问到当前作用域下包含的内层作用域的变量。同样,在不同作用域中也是不能互相访问彼此的变量的。
//局部作用域
function fun(){
var a = 1;
console.log(a);//1
}
console.log(a);//a is not defind
//全局作用域
var b = 1
function fun(){
var a = 1;
console.log(a);//1
console.log(b);//1
}
console.log(a);//a is not defind
fun()
console.log(b);//1
二、闭包的特点:
- 函数嵌套函数
- 可以在一个函数外部访问函数内部的变量
- 参数和变量不会被垃圾回收机制回收
function fun(){
var num = 10;
return function(){
num++;
}
}
fun();//ƒ (){num++;}
function demo() {
let a = 1;
return function () {
return a;
}
}
let b = demo();
console.log(b()); // 1
在这段代码中,demo()中的返回值是一个匿名函数,这个函数在demo()作用域内部,所以它可以获取demo()作用域下变量a的值,将这个值作为返回值赋给全局作用域下的变量b,实现了在全局变量下获取到局部变量中的变量的值。
闭包函数变量的意义:
1、fun()开启一个函数执行空间 并把这个函数执行空间结果返回res
2、res是全局变量 这个变量是不会被销毁的
3、res的值不能被销毁
4、res的值依赖fun()这个函数执行,所以fun函数执行空间也不能被销毁
5、fun()函数执行空间不能被销毁,所以fun函数执行空间也不能被销毁
6、让变量始终保持在内存中
function fun(){
var num =10;
console.log(num);//10
return function(){
num++;
console.log(num);//无返回值
}
}
let res = fun()
res()//11
res()//12
res()//13
闭包的用途:
闭包前:
for (var i = 0; i < btns.length; i++) {
// console.log(btns[i]);
btns[i].onclick = (function (n) {
// n 就是函数中的局部变量
// 就是把这个函数返回给每一个元素的点击事件
return function () {
// i 的值 始终都为4
// 事件驱动程序
document.querySelector(".active").classList.remove("active");
this.classList.add("active");
// 显示对应的li 那么需要获取点击这个元素的索引值
// console.log(n);
document.querySelector('.show').classList.remove('show');
// lis[n].style.display = 'block';
lis[n].classList.add('show');
console.log(lis[n]);
};
})(i);
// i 就是给 n赋值
}
闭包后:闭包后的代码简单易懂
for (let i = 0; i < btns.length; i++) { btns[i].onmouseover=function () { console.log(i);
document.querySelector(".active").classList.remove("active"); this.classList.add("active");
document.querySelector('.show').classList.remove('show'); lis[i].classList.add('show'); }; }
经典例子:闭包定时器
1、当变量为全局变量时
for (var i = 0; i < 5; ++i) {//全部变量的时候
setTimeout(function () {
console.log(i);
}, 1000)
}
结果:
2、当变量为局部变量时:
for (let i = 0; i < 5; ++i){
setTimeout(function(){
console.log(i);
}, 1000)
}
上面代码中,我们引入闭包来保存变量i
,将setTimeout放入立即执行函数中,将for循环中的循环值i
作为参数传递,1000毫秒后同时打印出0 1 2 3 4
。
for (var i = 0; i < 5; i++){
(function(i){
setTimeout(function(){
console.log(i);
}, i*500);
})(i);
}
结果: