闭包在js中是比较难懂的一个概念,因为闭包是比较抽象的一个概念,不过只要你理解了JS的解析过程及作用域,要理解闭包也不是难事。 那么闭包到底是什么呢?
闭包:在函数内部定义了另外一个函数, 这个函数引用了外部函数(或者父函数的父函数)的自由变量,那么就形成了闭包,这个函数也叫做闭包函数。
闭包可以看的见吗? 我们借助浏览器是可以看到的:
<script type="text/javascript">
function f()
{
var a = 10;
var b = 20;
function g()
{
console.log(a);
}
g();
}
f();
</script>
在console.log(a)那行打断点,运行程序,截图如下:
Closure(f)即为闭包, 当然在不同的浏览器中表现不一样,在safari浏览器中,变量a、b、函数g都在闭包对象中。
我们也可以这样理解闭包:闭包是一个对象,这个对象包含一个函数以及函数捕获的变量。
使用闭包有什么好处呢?
1、可以减少全局变量,一个html页面可能会引用多个js文件,全局变量越小,冲突的几率就越少。
实现一个功能,每调用一次,计数器加1。
<script type="text/javascript">
function add()
{
var count = 0;
alert(count++);
}
add();
add();
</script>
以上代码,add函数不论调用多少次,count总是为1; 简单的处理就是把count声明为全局变量,即在函数外面定义;这无疑会增加全局变量的个数,下面用闭包来实现:
<script type="text/javascript">
function add()
{
var count = 0;
return function ()
{
count++;
alert(count);
}
}
var result = add();
result();
result();
</script>
分析:add函数每次调用时,都会创建一个词法环境对象Le{count:0}, add返回的函数result的作用域等于add.Le即result.[[scope]] == add.le, 当result调用时,会创建自己的词法环境result.Le,result.Le指向result.[[scope]], 形成作用域链。而result.Le中并不存在count变量,所以向上查找,每次找到的都是add.le中count。
2、可以减少传递给函数参数的数量
<script type="text/javascript">
function funFac(base)
{
return function (max){
var sum = 0;
for(var i = 1; i <= max; i++)
{
sum += i;
}
sum += base;
return sum;
}
}
var f1 = funFac(100);
alert(f1(5));
alert(f1(10));
var f2 = funFac(200);
alert(f2(5));
alert(f2(10));
</script>
有了前面的分析,这段代码看起来是不是简单呢?
3、封装
<script type="text/javascript">
(function(){
var a = 10;
function getA(){
return a;
}
function setA(val)
{
a = val
}
window.getA = getA;
window.setA = setA;
})();
alert(getA());
setA(20);
alert(getA());
</script>
总结:闭包的本质就是函数的作用域链。