文章目录
  1. 1. 8.2.4 间接调用
  • 8.6 闭包
  • 8.2.4 间接调用

    javascript中的两个方法call()和apply()可以用来间接地调用函数。两个方法都允许显式指定调用所需的this值,也就是说,任何函数可以作为任何对象的方法来调用,哪怕这个函数不是那个对象的方法。call()方法使用它自有的实参列表作为函数的实参,apply()方法则要求以数组的形式传入参数。

    8.6 闭包

    和其他大多数现代编程语言一样,Javascript也采用词法作用域,也就是说,函数的执行依赖于变量作用域,这个作用域是在函数定义时决定的,而不是函数调用时决定的。为了实现这种词法作用域,Javascript函数对象的内部状态不仅包含函数的代码逻辑,还必须引用当前的作用域链。函数对象可以通过作用域链相互关联起来,函数体内部的变量都可以保存在函数作用域内,这种特性被称为“闭包”。
    从技术的角度上讲,所有的javascript函数都是闭包:它们都是对象,它们都关联到作用域链。

        var scope = "global scope";      // 全局变量
        function checkScope() {
            var scope = "local scope";    // 局部变量
            function f() { return scope; }   // 在作用域中返回这个值
            return f();
        }
        checkScope();                      // => "local scope"
    

    checkScope() 函数声明了一个局部变量,并定义了一个函数f(),函数f()返回了这个变量的值,最后将函数f()的执行结果返回。你应当非常清楚为什么调用checkScope()会返回”local scope”。现在我们对这段代码做一点改动:

        var scope = "global scope";
        function checkScope() {
            var scope = "local scope";
            function f() { return scope; }
            return f;
        }
        checkScope()();         //  依然返回"local scope"
    

    在这段代码中,我们将函数内的一对圆括号移动到了checkScope()之后。checkScope()现在仅仅返回函数内嵌套的一个函数对象,而不是直接返回结果。
    回想一下词法作用域的基本规则:javascript函数的执行用到了作用域链,这个作用域链是函数定义的时候创建的。嵌套的函数f()定义在这个作用域链里,其中的变量scope一定是局部变量,不管在何时何地执行函数f(),这种绑定在执行f()时依然有效。因此最后一行代码返回”local scope”。简言之,闭包这个特性强大到让人吃惊:它们可以捕捉到局部变量(和参数),并一直保存下来,看起来像这些变量绑定到了在其中定义它们的外部函数。

    闭包
    在3.10.3节中定义了作用域链。我们将作用域链描述为一个对象列表,不是绑定的栈。每次调用javascript函数的时候,都会为之创建一个新的对象用来保存局部变量,把这个对象添加至作用域链中。当函数返回的时候,就从作用域链中将这个绑定变量的对象删除。如果不存在嵌套的函数,也没有其他引用指向这个绑定对象,它就会被当做垃圾回收掉。如果定义了嵌套的函数,每个嵌套的函数都各自对应一个作用域链,并且这个作用域链指向一个变量绑定对象。但如果这些嵌套的函数对象在外部函数中保存下来,那么它们也会和所指向的变量绑定对象一样当做垃圾回收。但是如果这个函数定义了嵌套的函数,并将它作为返回值返回或者存储在某处的属性里,这时就会有一个外部引用指向这个嵌套的函数。它就不会被当做垃圾回收,并且它所指向的变量绑定对象也不会被当做垃圾回收。

    文章目录
    1. 1. 8.2.4 间接调用
  • 8.6 闭包