「这是我参与11月更文挑战的第8天,活动详情查看:2021最后一次更文挑战」
代码块
如果在代码块{...}内声明一个变量,则这个变量只在该代码块内可见(前提是用let声明)。例如
因此我们可以用它来隔离一段代码,使该段代码执行自己的任务,并使用仅属于自己的变量。
如果没有代码块则会直接报错
对于 if,for 和 while 等,在 {...} 中声明的变量也仅在内部可见;
嵌套函数
基础使用
当一个函数是在另一个函数中创建的时,该函数就被称为“嵌套”的。如
嵌套函数作为结果返回
可以返回一个嵌套函数:作为一个新对象的属性或作为结果返回。(下面我们会针对这个示例做一个具体的分析)
词法环境
变量
- 变量是特殊内部对象的属性,与当前正在执行的(代码)块/函数/脚本有关。
- 操作变量实际上是操作该对象的属性。
在 JavaScript 中,每个【运行的函数】,【代码块 {...}】 以及整个脚本,都有一个被称为 词法环境(Lexical Environment) 的内部(隐藏)的关联对象。
“词法环境”是一个规范对象(specification object):它仅仅是存在于 编程语言规范 中的“理论上”存在的,用于描述事物如何运作的对象。我们无法在代码中获取该对象并直接对其进行操作。
函数声明
函数也是一个值,就像变量一样。不同之处在于函数声明的初始化会被立即完成。所以我们可以在(函数声明)的定义之前调用函数声明。
内外部的词法环境
在一个函数运行时,在调用刚开始时,会自动创建一个新的词法环境以存储这个调用的局部变量和参数。
如以下的函数示例
在这个函数调用期间,我们有两个词法环境:内部一个(用于函数调用)和外部一个(全局):
- 内部词法环境与
say的当前执行相对应。它具有一个单独的属性:name,函数的参数。我们调用的是say("John"),所以name的值为"John"。 - 外部词法环境是全局词法环境。它具有
phrase变量和函数本身。
内部词法环境引用了 outer。
在这个示例中,搜索过程为:
- 对于
name变量,当say中的alert试图访问name时,会立即在内部词法环境中找到它。 - 当它试图访问
phrase时,然而内部没有phrase,所以它顺着对外部词法环境的引用找到了它。
返回函数
再来看下上面【嵌套函数作为结果返回】部分中的示例
function makeCounter() {
let count = 0;
return function() {
return count++;
};
}
let counter = makeCounter();
每次 makeCounter() 调用的开始,都会创建一个新的词法环境对象,以存储该 makeCounter 运行时的变量。因此,有两层嵌套的词法环境。
在执行 makeCounter() 的过程中创建了一个仅占一行的嵌套函数:return count++。此时只是创建了它,还没有运行。
所有的函数在“诞生”时都会记住创建它们的词法环境。所有函数都有名为 [[Environment]] 的隐藏属性,该属性保存了对创建该函数的词法环境的引用。
因此,counter.[[Environment]] 有对 {count: 0} 词法环境的引用。这就是函数记住它创建于何处的方式,与函数被在哪儿调用无关。[[Environment]] 引用在函数创建时被设置并永久保存。
当调用 counter() 时,会为该调用创建一个新的词法环境,并且其外部词法环境引用获取于 counter.[[Environment]]:
当 counter() 中的代码查找 count 变量时,
- 会首先搜索自己的词法环境(为空,因为那里没有局部变量),
- 然后是外部
makeCounter()的词法环境,并且在哪里找到就在哪里修改。 - 在变量所在的词法环境中更新变量。
所以当调用多次 counter() 时,count 变量将在同一位置增加到 2,3 等。
参考资料:
🎨【点赞】【关注】不迷路,更多前端干货等你解锁
往期推荐