当前位置: 首页 > Web前端 > JavaScript

作用域(二)——词法作用域

时间:2023-03-26 21:18:57 JavaScript

在上一篇文章中,我们将“作用域”定义为一组规则,用于管理引擎如何在当前作用域和嵌套的子动作域中通过变量查找标识符名称。作用域有两种主要的工作模型。第一个是大多数编程语言最常用的词法作用域,我们将深入讨论这个作用域。另一种叫做动态作用域,在某些编程语言中(如Bash脚本,Perl中的一些模式等)仍在使用。简单的说,词法作用域就是词法阶段定义的作用域。换句话说,词法作用域取决于您在编写代码时放置变量和块作用域的位置,因此当词法处理器处理代码时,它会保留作用域(它大部分时间都会这样做)。对于一些比较特殊的,会有一些欺骗性的词法作用域,主要是JavaScript中的with和eval关键字,不建议在项目中使用。考虑以下代码:functionfoo(a){varb=a*2;函数bar(c){console.log(a,b,c)}bar(b*3);}foo(2);//2,4,12在这个例子中,有三个作用域是逐级嵌套的。为了帮助理解,可以将它们想象成几个逐步包含的气泡。1.包含整个全局作用域,后一个标识符:foo2,包含foo创建的作用域,共有三个标识符:a、bar和b3,包含bar创建的作用域,其中只有一个标识符符号:cscopebubble是由相应的scopeblock代码写在哪里决定的,它们是一步步被包含进来的。我们将在以后的文章中讨论不同类型的作用域,但现在最好假设每个函数都创建一个新的气泡作用域。Bar的气泡完全包含在foo创建的气泡中的唯一原因是因为那是我们希望定义函数bar的地方。请注意,这里所说的气泡是严格包含在内的。我们不是在谈论可以跨越边界的气泡维恩图。换句话说,任何函数的气泡都不能(部分)同时出现在两个外部作用域气泡中,就像任何函数都不能同时部分出现在两个父函数中一样。(简单理解就是内部作用域一定是上层作用域的子集。)作用域气泡的结构和相互之间的位置关系为引擎提供了足够的位置信息,关系为引擎提供了足够的位置信息。引擎使用这些信息来查找标识符的位置。在前面的代码片段中,引擎执行console.log语句并查找对三个变量a、b和c的引用。它开始在最里面的作用域中查找,即bar函数的作用域气泡。引擎在这里找不到a,就会到上层继续在嵌套的foo范围内查找。A在这里找到,所以引擎使用这个引用。b也是同样的道理。对于c,引擎在bar中找到它。如果a和c都存在于bar和foo内部,那么congsole.log可以直接使用bar中的变量,而无需在foo外部查找。范围查找在找到第一个匹配标识符时停止。在多级嵌套作用域中可以定义同名标识符,称为“阴影效应”(内部标识符“影子”外部标识符)。无论阴影效应如何,范围查找总是从运行时所在的最内层范围开始,逐步向外或向上进行,直到遇到第一个匹配的标识符。全局变量会自动成为全局对象(如浏览器中的window对象)的属性,因此不能直接通过全局对象的词法名称访问,而是通过全局对象属性的引用间接访问。window.a可以通过这种技术访问那些被同名变量遮蔽的全局变量,但是如果非全局变量被遮蔽,则无论如何都无法访问。无论函数在何处被调用或如何调用,其词法范围仅由声明函数的位置决定。词法范围查找仅查找第一级标识符,例如a、b和c。如果代码中引用了foo.bar.baz,词法作用域查找只会尝试找到foo标识符。找到这个变量后,对象属性访问规则将分别接管对bar和baz属性的访问。参考资料:《你不知道的JavaScript(上)》也可以扫描下方二维码,关注我微信公众号,蜗牛满栈。