说到闭包,大家可能会比较头疼,也是面试题比较常考的。接下来就形象的来说一些闭包。
程序运行的法则——作用域
说起闭包,首先肯定要说的是作用域,这里也简单说一下。
我们平时在写代码的时候经常会遇到’“xxx” is not defined’,那究竟程序是怎么判断是不是’defined’的呢?这时候肯定要制定一些规则,程序怎么去找这些函数、变量。
首先作用域就是这些函数、变量可用的范围。也就是说我想要用这些变量、函数的安全范围,超出作用域范围外使用这些定义的量就会是“undefined”。那我在用这个定义的变量的时候程序是怎么判断它有没有在作用域范围内呢。这就是作用域链的定义。
当我们在使用一个变量或者函数时,程序会首先在本层函数里找这个变量或者函数,当没有时,就会向外层去寻找这个变量、函数,当外层也没有时,就再向外层的外层,以此类推,直到找到最外层也就是全局变量或者函数那里,如果还没有,那就是可以判断这个函数、变量是“undefined”的了。
什么是闭包
既然有这些规则在这,但是有的时候,我们会说,那我有需求想要访问不在我作用域范围内的函数、或者变量怎么办。其实这就是闭包了。
闭包:简单来说其实就是:被包在函数内部的变量,在外部被操作到了。
按照我们说的作用域来说,就是在作用域外访问到了某个变量。
百度上的解释是:闭包就是能够读取其他函数内部变量的函数。
其实简单理解来说也就是:闭包就是将函数内部和函数外部连接起来的桥梁。
闭包形成的条件
那我们怎么做才能形成闭包——也就是访问不在作用域内的变量呢?
这里有形成闭包的三个条件:
- 外层函数中要有局部变量;
- 内层函数中要操作外层函数的局部变量;
- 外层函数将内层函数返回给外部变量。
只要满足这三个条件,就能形成闭包。
举个例子:
// 外层函数
function bibao(){
// 局部变量
var a = 10;
// 内层函数
var neibu = function(){
//操作局部变量
a++;
console.log(a);
}
// 返回内层函数
return neibu;
}
var jeishou = bibao();
jeishou(); //打印出来是11
至此我们在外层返回到了局部变量“a”,便形成了闭包。
闭包的经典案例
案例一:点击按钮显示按钮的index
<button>我是按钮</button>
<button>我是按钮</button>
<button>我是按钮</button>
<button>我是按钮</button>
<button>我是按钮</button>
<button>我是按钮</button>
<button>我是按钮</button>
<button>我是按钮</button>
<button>我是按钮</button>
var btns = document.querySelectorAll('button');
for(var i = 0;i<btns.length;i++){
// 自调用匿名函数 形参i相当于局部变量
(function(i){
btns[i].onclick = function(){
alert(i);
}
})(i)
}
案例二:点击不同按钮,div字号变化
<button>点击文字变成100px</button>
<button>点击文字变成200px</button>
<button>点击文字变成300px</button>
<div>文字</div>
var div = document.querySelector("div");
btns[0].onclick = setSize(100);
btns[1].onclick = setSize(200);
btns[2].onclick = setSize(300);
function setSize(num){
var fn = function(){
div.style.fontSize = num + "px";
}
return fn;
}
戏说闭包
之前听过一个老师讲的闭包,比较形象一点,可能会加深记忆。
可以把外层函数比作是一个公寓,把变量比作藏于公寓中的“三儿",然后内层函数是管家。当整个函数赋值给一个朝阳群众,这样的意义便是:“藏于别墅里的三儿被朝阳群众通过管家发现了”
例子:
function bieshu(){
var san = 100;
function guanJia(){
san++;
console.log(san);
}
return guanJia;
}
var chaoyangqunzong = bieshu();
chaoyangqunzong(); //101
希望这样可以加深你的记忆,让你对闭包理解的更加清晰一些。