「建议收藏」词法作用域作用域可以视为一套规则 , 这套规则用来管理引擎如何在当前作用域以及嵌套的子作用域根据标识符名称进行变量查找 。
作用域共有两种主要的工作模型 , 第一种是最为普遍的 , 被大多数编程语言所采用的词法作用域 , 我们会对这种作用域进行深入讨论 。 另外一种叫做动态作用域 , 仍有一些编程语言在使用 。
词法阶段大多数标准化语言编译器的第一个工作阶段叫做词法化 , 词法化的过程会对源代码中的字符串进行检查 , 如果是有状态的解析过程 , 还会赋予单词意义 。
这个概念是理解词法作用域 , 及其名称来历的基础 。
简单的说 , 词法作用域就是定义在词法阶段的作用域 。 换句话说 , 词法作用域是由你在写代码时将变量和块作用域写在哪里来决定的 , 因此当词法分析器处理代码时会保持作用域不变 。
function foo(a){
var b = a * 2
function bar(c){
console.log(abc)
bar(b*3)
foo(2)
在这个例子中有三个逐级嵌套的作用域 , 为了帮助理解 , 可以将它们想象成几个逐级包含的气泡 。
?最外面的是整个全局作用域 , 其实只有一个标识符:foo 。 ?包含着 foo 所创建的作用域 , 其中有三个标识符: a、bar 和 b?包含着 bar 所创建的作用域 , 其中只有一个标识符: c
作用域气泡由其对应的作用域块代码写在哪里决定 , 它们是逐级包含的 , 每个函数都会创建一个新的作用域气泡 。
bar 的气泡完全被包在 foo 所创建的气泡中 , 唯一的原因是那里就是我们希望定义函数 bar 的位置 。
查找作用域气泡的结构和互相之间的位置关系 , 给引擎提供了足够的位置信息 , 引擎用这些信息查找标识符的位置 。
在上一个代码片段中 , 引擎执行 console.log 声明 , 并查找 a、b 和 c 三个变量的引用 。 它首先从最内部的作用域 , 也就是 bar 函数的作用域气泡开始查找 。 引擎无法在这里找到 a , 因此会去上一层所嵌套的 foo 的作用域中继续查找 , 在这里找到了 a , 因此引擎使用了这个引用 。 对 b 来说也是一样的 。 而对 c 来说 , 引擎在 bar 中就找到了它 。
如果 a、c 都存在于 bar 和 foo 的内部 , console.log 就可以直接使用 bar 中的变量 , 而无需去 foo 中查找 。
作用域查找会在找到第一个匹配的标识符时停止 。 在多层嵌套作用域中可以定义同名的标识符 , 这叫做「遮蔽效应」 , 内部的标识符遮蔽了外部的标识符 。 抛开遮蔽效应 , 作用域查找始终从运行时所处的最内部作用域开始 , 逐级向外或者说向上进行 , 直到遇见第一个匹配的标识符为止 。
无论函数在哪里被调用 , 也无论如何被调用 , 它的词法作用域都只由函数被声明时所处的位置决定 。
词法作用域只会查找一级标识符 , 比如 a、b 和 c 。 如果代码中引用了 foo.bar.baz , 词法作用域查找只会试图查找 foo 标识符 , 找到这个变量后 , 对象属性访问规则会分别接管 bar 和 baz 属性的访问 。
注:这点很重要 , 这对传递参数提供了无数可能 。
欺骗词法如果词法作用域完全由写代码期间函数所声明的位置来定义 , 怎样才能在运行时来修改词法作用域呢?
- 安卓|这种安卓「机皇」做得很好,下次别做了
- shopee|经常被割韭菜的我,给shopee小白的一点建议(看懂可避坑)
- VR|ZOAN:使用Varjo在元宇宙中建立虚拟总部
- 微信|微信吃存储?教你 5 个方法给微信「瘦身」
- 数据库|「建议收藏」词法作用域
- ios15|iOS 15.5 Beta1:建议看完果粉体验反馈再升级!
- Population|支持枪械改造,VR“吃鸡”游戏「Population: One」重大更新6月发布
- VR城建游戏|九折促销,VR城建游戏「Cities:VR」Quest 2版4月28日上线
- vrmod|「半衰期:爱莉克斯」VRMOD“Levitation”即将发布
- meta|给自媒体人的10条建议