5分钟入门闭包

2017-07-14  本文已影响0人  佳勋学长

理解闭包前先要理解两个概念:作用域和作用域链。
一、作用域分为:

  1. 全局作用域

  2. 函数作用域

     var a = 100
     function fn() {
       var a = 200
       console.log('local: ' + a)
     }
     fn() // local: 200
     console.log('global: ' + a) // glocal: 100
    

执行上面的代码可以看到,第一个a是定义在全局作用域里的,第二个a是定义在函数作用域里的。在全局作用域的变量a和在函数作用域变量a互不影响。
注意:没有块级作用域。

二、作用域链

var a = 100
function f1() {
  var b = 200
  function f2() {
    var c = 300
    console.log(a)
    console.log(b)
    console.log(c)
  }
  f2()
}
f1() // 100 200 300

执行以上代码,依次打印出a, b, c的值100,200,300。其中a是定义在全局作用域里,b是定义在函数f1作用域里,c是定义在函数f2作用域里。

当代码执行到函数f2里的console.log(a)的时候,首先会在函数f2的作用域找,没有 --> 到父级作用域即函数f1的作用域里面找,也没有 --> 再到父级作用域即全局作用域里面找,有,打印。

同理当console.log(b)的时候首先会在函数f2的作用域找,没有 --> 到父级作用域即函数f1的作用域里面找,有,打印。

这三个作用域组成的有序集合(f2 -- f1 -- window)就是作用域链。

注意:函数的父级作用域指的是函数定义时候的决定的,而不是执行的时候。即函数在什么地方定义,父级作用域就在哪里。

三、闭包
闭包有两种应用场景:

  1. 函数作为返回值

     function fn() {
       var a = 100
       return function() {
         console.log(a)
       }
     }
     var f1 = fn()
     var a = 200
     f1() // 100
    

fn返回一个函数,赋值给f1,执行f1()即执行fn的返回函数。返回函数在定义时的父级作用域是fn,因此返回函数里的变量a会到函数fn的作用域去找,而与函数f1执行时定义的全局作用域里的变量a无关。

  1. 函数作为参数传递

     function f1() {
       var a = 100
       return function() {
         console.log(a)
       }
     }
     var fn = f1()
     function f2(f) {
       var a = 200
       f()
     }
     f2(fn)  // 100
    

函数f2接收一个函数作为变量传入,执行函数f即执行函数f1,剩下的代码执行过程和场景1同理。

总结:闭包的特性让我们可以在函数作用域之外,通过作用域链访问到函数作用域内的变量,但是无法对其进行修改。

上一篇下一篇

猜你喜欢

热点阅读