原来JavaScript的闭包是这么回事(2)

第4-5行,函数结束执行,本地执行上下文被销毁,变量x和ret被清除,它们不再存在。上下文弹出调用栈,返回值被返回到调用上下文。在这种情况下,调用上下文就是全局执行上下文,因为函数addTwo是从全局执行上下文中调用的。

现在我们从在步骤4中暂停的位置继续。返回值(数值5)被分配给变量b。

在第7行,变量b的内容会在控制台中打印出来。在这个例子中,数值为5。

对于一个非常简单的程序来说,这样的解释显得太过冗长,但我们甚至都还没有提到闭包。我保证会说到那里,但首先我们需要说一些其他的。

词法作用域

我们需要了解词法作用域的某些方面,看下面的例子。

1: let val1 = 2 2: function multiplyThis(n) { 3: let ret = n * val1 4: return ret 5: } 6: let multiplied = multiplyThis(6) 7: console.log('example of scope:', multiplied)

在本地执行上下文和全局执行上下文中都有一些变量。JavaScript的一个复杂之处在于它的变量查找过程。如果它在本地执行上下文中找不到变量,就会在调用上下文中查找。如果没有在调用上下文中找到,最后会在全局执行上下文查找。如果还是没有找到,那它就是undefined。

在全局执行上下文中声明一个新变量val1,并赋值为2。

第2-5行,声明一个新变量multiplyThis,并将一个函数定义赋给它。

第6行,在全局执行上下文中声明一个新变量multiplied。

从全局执行上下文内存中获取变量multiplyThis,并将其作为函数执行。将数值6作为参数传递进去。

新函数调用就是新的执行上下文。创建一个新的本地执行上下文。

在本地执行上下文中,声明变量n,并赋值为6。

第3行,在本地执行上下文中声明变量ret。

第3行,用两个操作数执行乘法运算:变量n和val1的内容。在本地执行上下文中查找变量n,我们在步骤6中声明了它,它的内容是数值6。在本地执行上下文中查找变量val1,本地执行上下文中没有标记为val1的变量。我们从调用上下文中查找,调用上下文也就是全局执行上下文。让我们在全局执行上下文中查找val1。是的,它就在那里。它在步骤1中定义,值为数值2。

第3行,将两个操作数相乘,并将结果指定给变量ret。6 * 2 = 12。ret现在是12。

返回ret变量,本地执行上下文及其变量ret和n被销毁。变量val1不会被销毁,因为它是全局执行上下文的一部分。

回到第6行,在调用上下文中将数值12分配给变量multiplied。

第7行,在控制台中显示变量multiplied的值。

所以在这个例子中,我们需要记住一个函数可以访问在其调用上下文中定义的变量,这种现象的正式名称是词法作用域。

返回函数的函数

在第一个示例中,函数addTwo返回一个数值。请记住,函数可以返回任何内容。让我们看一个返回函数的函数的示例,因为这对理解闭包来说很重要。

1: let val = 7 2: function createAdder() { 3: function addNumbers(a, b) { 4: let ret = a + b 5: return ret 6: } 7: return addNumbers 8: } 9: let adder = createAdder() 10: let sum = adder(val, 8) 11: console.log('example of function returning a function: ', sum)

让我们来逐步分析它的执行过程。

第1行,我们在全局执行上下文中声明一个变量val,并将数值7赋给该变量。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/c447d03ec21c8cafb2e1d8273e639831.html