为什么内部函数没有访问外部函数依然形成了闭包?

新手上路,请多包涵
  1. 为什么下方代码fn2执行的过程中没有访问foo的变量,依然形成了闭包?
  2. 代码:

    function foo() {
        var a = 10;
    
        function fn1() {
            return a;
        }
    
        function fn2() {
            return 10;
        }
    
        fn2();
    }
    
    foo();
  3. chrome截图信息
    clipboard.png
阅读 2k
1 个回答

这个要理解闭包到底是什么

很多地方都讲闭包就是内部函数访问外部函数变量便形成了闭包,这种说法没有问题,这样确实是形成了闭包,但是这种说法很容易造成误解,这只是闭包的形式。

我觉得,要理解闭包,就要理解其形成的根本原因——作用域,个人认为,闭包就是函数作用域的利用。

看你的代码:

function foo() {
    var a = 10;

    function fn1() {
        return a;
    }

    function fn2() {
        return 10;
    }

    fn2();
}

这个代码内部形成了三个作用域:

  1. foo作用域: Foo
  2. fn1作用域: Fn1
  3. fn2作用域: Fn2

作用域是有链式关系的,当函数创建的时候,保存了一个作用域链

因此三个作用域可以表示为:

  1. foo作用域: Foo -> Global
  2. fn1作用域: Fn1 -> Foo
  3. fn2作用域: Fn2 -> Foo

所以,无论fn1fn2是否访问外部函数foo,foo作用域Foofn1fn2是可见的,自然也就形成了闭包

fn1利用了闭包,而fn2没有利用闭包,但不影响闭包的形成
无论你用或不用,闭包就在那里

无论你用或不用(闭包特性),闭包(一旦形成)就在那里


经题主提醒,调试之后发现:

function foo() {
    var a = 10;

    function fn1() {
        return 10;
    }

    function fn2() {
        return 10;
    }

    fn2();
}

这样的代码,Chrome下作用域链与上文提出的有些差别():

  1. foo作用域: Foo -> Global
  2. fn1作用域: Fn1 -> Global
  3. fn2作用域: Fn2 -> Global

而同样的代码,FireFox给出的内容要多一点,但也能进一步看出引擎是有优化能力的:

  1. foo作用域: Foo -> Global
  2. fn1作用域: Fn1 -> Foo(optimized away) -> Global
  3. fn2作用域: Fn2 -> Foo(optimized away) -> Global

可以看到optimized away这样的描述,也就是说,引擎实际上是将其优化掉的

因此内部函数访问外部函数变量应该是一种条件,如果这个内部函数没有访问过外部函数中的变量,其作用域链中并没有外部函数的作用域。(也许是引擎的一种优化,个人猜测)

具体细节,还要进一步去了解

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题