图解词法做用域与做用域链

做用域

做用域是指程序源代码中定义变量的区域。

做用域规定了如何查找变量,也就是肯定当前执行代码对变量的访问权限。

JavaScript 采用词法做用域(lexical scoping),也就是静态做用域。

想了解更多关于做用域的问题推荐阅读《你不知道的JavaScript上卷》第一章(或第一部分),
从编译原理的角度说明什么是做用域。归纳的说做用域就是一套设计良好的规则来存储变量,而且以后能够方便地找到这些变量。
复制代码

词法做用域

在你不知道的javascript上卷中是这样定义的:词法做用域就是定义在词法阶段的做用域。换句话说,词法做用域是由你在写代码时将变量和块做用域写在哪里来决定的,所以当词法分析器处理代码时会保持做用域不变(大部分状况下是这样的)。javascript

在JS中词法做用域的规则:java

  • 函数容许访问函数外部的数据
  • 整个代码结构中只有函数能够限定做用域
  • 做用规则首先使用提高规则分析
  • 若是当前做用域中有了名字了,就不考虑外面的名字

例1bash

var a = 2;
function foo() {
  var a = 3;
  console.log(a); // 3
}
foo();
复制代码

例2函数

function foo() {
  console.log(a); // 2
}
function bar() {
  var a = 3;
  foo();
}
var a = 2;
bar();
复制代码

做用域链

只有函数才能制造做用域结构,那么只要是代码,至少有一个做用域,即全局做用域。ui

凡是代码中有函数,那么这个函数就构成另外一个做用域。若是函数中还有函数,那么在这个做用域中就又能够诞生一个做用域,那么将这样的全部做用域列出来,能够有一个结构:函数内指向函数外的链式结构。spa

以上面例2:设计

function foo() {
  console.log(a); // 2
}
function bar() {
  var a = 3;
  foo();
}
var a = 2;
bar();
复制代码
  • 全局做用域,有三个标识符:foo、bar、a
  • bar 所建立的做用域,其中有一个标识符:a

做用域是由代码写在哪里决定的,而且是逐级包含的。code

咱们用级链来表示一下以上代码块:cdn

从图中咱们能够看到:函数foo和bar以及变量 a=2, 在1级链,而bar下又能够展开2级链,2级链上有a=3。程序bar()调用进入中间2级链,而bar中又调用了foo函数,此时程序进入foo的做用域链,按照向上查找的原则,程序会从这一条链向上查找,首先2级链没有a,向上到达1级链,恰好1级链上有a=2,因此就直接使用2,程序最后的结果就是打印2。

因此不管函数在哪里被调用,也不管它如何被调用,它的词法做用域都只由函数被声明时所处的位置决定。blog

实践

var scope = "global scope";
function checkscope(){
  var scope = "local scope";
  function f(){
    return scope;
  }
  return f();
}
checkscope();
复制代码

相关文章
相关标签/搜索