我从来不理解JavaScript闭包,直到有人这样向我解释它( 二 )

  • 仍然是第3行,需要执行一个相加操作 。首先我们需要x的值,JavaScript会寻找一个变量x,它会首先在addTwo执行上下文中寻找,找到了一个值为3 。第二个操作数是数字2 。两个相加结果为5就被分配给变量ret 。
  • 第4行,我们返回变量ret的内容,在addTwo执行上下文中查找,找到值为5,返回,函数结束 。
  • 第4-5行,函数结束 。addTwo执行上下文被销毁,变量x和ret被释放,它们已经不存在了 。addTwo 执行上下文从调用堆栈中弹出,返回值返回给调用上下文,在这种情况下,调用上下文是全局执行上下文,因为函数addTwo是从全局执行上下文调用的 。
  • 现在我们继续第4步的内容,返回值5被分配给变量b,程序仍然在第6行 。
  • 在第7行,b的值 5 被打印到控制台了 。
  • 对于一个非常简单的程序,这是一个非常冗长的解释,我们甚至还没有涉及闭包 。但肯定会涉及的,不过首先我们得绕一两个弯 。
    词法作用域(Lexical scope)我们需要理解词法作用域的一些知识 。请看下面的例子:
    我从来不理解JavaScript闭包,直到有人这样向我解释它

    文章插图
     
    这里想说明,我们在函数执行上下文中有变量,在全局执行上下文中有变量 。JavaScript的一个复杂之处在于它如何查找变量,如果在函数执行上下文中找不到变量,它将在调用上下文中寻找它,如果在它的调用上下文中没有找到,就一直往上一级,直到它在全局执行上下文中查找为止 。(如果最后找不到,它就是 undefined) 。
    下面列出向个步骤来解释一下(如果你已经熟悉了,请跳过):
    1. 在全局执行上下文中声明一个新的变量val1,并将其赋值为2 。
    2. 第2-5行,声明一个新的变量 multiplyThis,并给它分配一个函数定义 。
    3. 第6行,声明一个在全局执行上下文 multiplied 新变量 。
    4. 从全局执行上下文内存中查找变量multiplyThis,并将其作为函数执行,传递数字 6 作为参数 。
    5. 新函数调用(创建新执行上下文),创建一个新的 multiplyThis 函数执行上下文 。
    6. 在 multiplyThis 执行上下文中,声明一个变量n并将其赋值为6 。
    7. 第 3 行 。在multiplyThis执行上下文中,声明一个变量ret 。
    8. 继续第 3 行 。对两个操作数 n 和 val1 进行乘法运算.在multiplyThis执行上下文中查找变量 n 。我们在步骤6中声明了它,它的内容是数字6 。在multiplyThis执行上下文中查找变量val1 。multiplyThis执行上下文没有一个标记为 val1 的变量 。我们向调用上下文查找,调用上下文是全局执行上下文,在全局执行上下文中寻找 val1 。哦,是的、在那儿,它在步骤1中定义,数值是2 。
    9. 继续第 3 行 。将两个操作数相乘并将其赋值给ret变量,6 * 2 = 12,ret 现在值为 12 。
    10. 返回ret变量,销毁multiplyThis执行上下文及其变量 ret 和 n。变量 val1 没有被销毁,因为它是全局执行上下文的一部分 。
    11. 回到第6行 。在调用上下文中,数字 12 赋值给 multiplied 的变量 。
    12. 最后在第7行,我们在控制台中打印 multiplied 变量的值
    在这个例子中,我们需要记住一个函数可以访问在它的调用上下文中定义的变量,这个就是词法作用域(Lexical scope) 。
    返回函数的函数在第一个例子中,函数addTwo返回一个数字 。请记住,函数可以返回任何东西 。让我们看一个返回函数的函数示例,因为这对于理解闭包非常重要 。看粟子:
    我从来不理解JavaScript闭包,直到有人这样向我解释它

    文章插图
     
    让我们回到分步分解:
    1. 第1行 。我们在全局执行上下文中声明一个变量val并赋值为 7 。
    2. 第 2-8 行 。我们在全局执行上下文中声明了一个名为 createAdder 的变量,并为其分配了一个函数定义 。第3-7行描述了上述函数定义,和以前一样,在这一点上,我们没有直接讨论这个函数 。我们只是将函数定义存储到那个变量(createAdder)中 。
    3. 第9行 。我们在全局执行上下文中声明了一个名为 adder 的新变量,暂时,值为 undefined 。
    4. 第9行 。我们看到括号(),我们需要执行或调用一个函数,查找全局执行上下文的内存并查找名为createAdder 的变量,它是在步骤2中创建的 。好吧,我们调用它 。
    5. 调用函数时,执行到第2行 。创建一个新的createAdder执行上下文 。我们可以在createAdder的执行上下文中创建自有变量 。js 引擎将createAdder的上下文添加到调用堆栈 。这个函数没有参数,让我们直接跳到它的主体部分.


      推荐阅读