JavaScript中的闭包

闭包的产生

我们都知道,在js中,全局变量可以在所有位置被访问,而局部变量,只能在局部变量所在的作用域和同一作用域内声明的函数使用。如下面这个例子:

function foo() {
   	let a = 10;
    function bar() {
        console.log(a);
    }
    bar();
}
foo(); // 10

console.log(a); // a is not defined

那么有没有什么办法,可以使得在函数作用域外面使用局部变量呢?我们把上面这个例子稍微改改:

function foo() {
    let a = 10;
    return function () {
        console.log(a);
    }
}
let bar =  foo();
bar(); // 10

可以看出,我们能在函数foo的作用域之外的地方观察到局部变量a了,其实在这里,就产生了闭包。这个闭包是由被外部变量bar所引用的「内部函数」和被内部函数所引用的「局部变量a」所组成的

在Chrome里的使用控制台查看Source,可以看到内部的匿名函数有个Closure,这个就是闭包,里面可以看到引用的变量a。其实用Chrome查看第一个例子,内部函数bar也有一个Closure,但是我个人更偏向于第二例子中,内部函数被外部引用的时候才算真正的闭包。

其实闭包形成的原因很容易理解,正常来说,函数foo执行完毕,它的执行上下文就会被销毁,但是内部函数引用了foo作用域中的变量a,foo作用域外的变量bar又引用了内部函数,就导致了即使函数foo执行完毕,它的执行上下文中的作用域也不会被销毁,毕竟还有东西被引用着。

return的必要性

函数中的return语句不是构成闭包的必要条件,还可以用其他的方式,使得外部可以引用内部函数:

function foo() {
    let a = 10;
   	window.bar = function () {
        console.log(a);
    }
}
foo();
bar(); // 10

这个例子里,foo函数内就直接给window定义了一个全局方法,使得内部函数被外部的window.bar所引用,也就形成了闭包。

function foo() {
   let a = 10;
   function bar() {
       console.log(a);
   }
   baz(bar)
}
function baz(fn) {
   fn();
}

foo(); // 10

上面这个例子内部函数就没有在全局作用域中被引用,而是被当做参数传递给另一个函数,在那个函数的作用域中被使用,此时也产生了闭包。

闭包的作用

  1. 外界可以读取函数作用域中的局部变量
  2. 把某个变量隐藏在函数作用域中,避免污染全局作用域

第一点前面的例子已经体现了出来,第二点我们用个经典的例子来说明:

let a = 1;
function add() {
    console.log(a);
    a++;
}
add(); // 1
add(); // 2
a = 10;
add(); // 10

在这里,我们想定义一个计数器,每调用一次,计数就+1,于是需要一个变量保存计数,但是又不能保存在函数中,不然每次调用都是同一个值。如果保存在全局中,那么计数变量不小心被修改之后,再次调用计数器函数,得到的结果就会和我们想要的不一样。

有了闭包之后,这个问题就好解决了:

function foo() {
    let a = 1;
    return function () {
        console.log(a);
        a++;
    }
}

let add1 = foo(); // 计数器1
add1(); // 1
add1(); // 2
add1(); // 3

let add2 = foo(); // 计数器2
add2(); // 1
add2(); // 2
add2(); // 3

我们把计数函数和计数变量放在一个函数作用域中,然后把计数函数作为外层函数的返回值,执行外层函数生成一个计数器,这样既保证了计数变量不会被随意修改,又能实现计数函数的功能,而且计数器1和计数器2互不影响。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值