Js学习笔记:闭包

# 一、前言

这个周末,注意力都在学习基础Js知识上面,刚好看到了闭包这个神圣的东西,所以打算把这两天学到的总结下来,算是巩固自己所学。也可能有些不正确的地方,也请大家看到了,麻烦在评论下提醒一下,算是互相学习了。

二、什么是闭包?

百度百科定义:闭包就是能够读取其他函数内部变量的函数。

在解释之前,得先讲讲作用域。先来看下面这个示例:

var a = 1;
function f(){
  var b = 2;
  console.log(a) // 1
}
console.log(b) // undefined

示例中包含了两种作用域,一种是属于全局的全局作用域,另一种是属于函数f的局部作用域。由于Javascript这种链式作用域(父作用域是可以被其子作用域访问的,而子作用域却不能被父作用域访问)的机制,使得示例最后一行输出了undefined

从此可以看出,无法从父作用域中访问子作用域。而我们再来看闭包的定义:闭包就是能够读取其他函数内部变量的函数。也就是闭包可以让我们从父作用域中访问到子作用域,具体怎么实现的呢?来看这个经典的例子:

function foo(){
    var a = 2;
    function bar(){
        console.log(a);
    }
    return bar;
}

var baz = foo();

baz(); // 2 -> 这就是闭包的效果

这个示例中,闭包就是函数bar。可以看到,我们通过在函数foo内部定义其子函数bar,并将其作为foo返回值,因为bar函数作用域可以访问foo的作用域,所以实现了从全局作用域访问foo函数作用域的效果。

三、闭包的应用

其实,平时你所写的代码中,早就用到了闭包,只是你还没发现而已。

本质上,无论何时何地,如果将函数当作值传递到其他地方使用(非函数所在作用域),你就已经使用了闭包。例如上面示例说的函数bar,我们将他传递到了全局作用域下,通过这种方式访问到本该不能访问的变量a

在定时器、事件监听器、Ajax请求、任何其他异步(或同步)任务中,只要使用了回调函数,实际上就是在使用闭包!

四、注意事项

闭包会让他所在作用域中的变量始终保存在内存中,而不会被垃圾回收机制回收。

function foo(p){
    function bar(){
        console.log(++p);
    }
    return bar;
}

var baz = foo(1);
baz(); // 2
baz(); // 3
baz(); // 4

var bazz = foo(2);

bazz(); // 3
bazz(); // 4
bazz(); // 5

baz(); // 5

看到了没,闭包的使用,函数调用之后,让其外层函数的内部变量(foo函数内的变量)始终保存在了内存中,而不会被回收。

值得注意的是,每次调用一次foo,都会生成一个新的闭包,都会在内存中保存下其外层函数的内部变量。因此要注意闭包的使用,否则会导致性能问题。

五、总结

闭包的作用:

  • 能够读取其他函数内部变量。
  • 让其他函数的内部变量始终保存在内存中。

参考:

  • 阮一峰的Javascript入门教程——闭包
  • 书籍:P43,你不知道的Javascript之闭包——上卷。

附:你不知道的Javascript系列电子书网盘链接, 密码:i8jf

你可能感兴趣的:(闭包,javascript)