本文内容:
- 什么是作用域?执行环境、变量对象;
- 什么是作用域链?
- 扩展:延长作用域链的两条语句with与catch
作用域链是javascript中常见的一个概念,想要理解作用域链,首先要理解好下面的两个概念:执行环境(常说的作用域)和变量对象。
作用域 == 执行环境
首先在其他语言中所说的作用域,在javascript中也叫执行环境,通常把作用域叫作执行环境,在javascript高级程序设计这本书中也是称为“执行环境”。
***那么到底什么是执行环境呢?***
执行环境
**执行环境**是javascript中的一个重要概念,**它定义了变量或者函数有权访问的数据。执行环境有两种类型:全局执行环境和局部执行环境,其中局部执行环境就是指函数。(也可以说javascript作用域有两种,全局作用域和局部作用域)**
全局执行环境是最外围的一个执行环境,如在Web浏览器中,全局执行环境就是window对象,因此所有全局变量和函数都是作为window对象的属性和方法创建的。
另外还有一个与之相关的重要概念,就是**变量对象**。
变量对象
每一个执行环境(每一个作用域)都有一个与之关联的**变量对象**,环境定义的所有变量和函数都保存在这个对象中(我们是无法访问到这个对象的,它的作用是解析器处理数据时会在后台使用它)。
作用域链
作用域链,顾名思义是一条链式结构,而这条链的每一个节点应该是作用域。又因为作用域即执行环境,上面说到每个执行环境都有一个与之关联的变量对象,因此可以说作用域链是这样的一条链:
作用域链中的每一个节点都是变量对象,变量对象上面保存着当前执行环境(作用域)中定义的变量和函数。作用域链的起点是当前执行的代码所在的执行环境对应的变量对象,下一个节点的变量对象则是来自包含环境,即上一个节点所在的执行环境的外部环境,再下一个节点是下一个外部环境,这样一层层延续直至到全局环境:全局环境的变量对象永远是作用域链的终点。
*知道了作用域链是什么,又有了另一个疑问作用域链这个东西是用来干什么的呢?*
作用域链的提出是为了在任何执行环境中访问变量或函数提供一个次序规则。通俗的说,你想访问一个变量,那么这个变量去哪里拿到呢,当前执行环境有,则取当前执行环境下的,这个无可厚非,当前环境没有定义的,则按照这个作用域链一级一级的搜索作用域链,若最后直到在全局环境中都还没有找到,则会报错,视为该变量没有定义。
var a = 1 function fn1 () { var b = 2 fn2() console.log(a,b) // 1,2 此时只能访问a,b, 访问c会报错 function fn2() { var c = 3 console.log(a,b,c) // 1, 2, 3,这里a,b,c全部能够访问 } } fn1() console.log(a) // 1 此时只能访问a, 访问b,c会报错
上面的代码涉及了三个执行环境:全局环境、fn1()的局部环境和fn2()的局部环境。在全局执行环境中只有一个变量a和函数fn1(),在函数fn1()的局部环境中有一个变量b和函数fn2(),但是在此执行环境中除了b和fn2还可以访问变量a,因为全局环境是它的父执行环境。在fn2()的局部环境中,有一个变量c,除了变量c,这个执行环境中还可以访问全局环境中的变量a和它的直接父执行环境fn1()中的变量b。下面的图可以形象的展示这个作用域链。
内部环境可以通过作用域链访问所有的外部环境。但外部环境不能访问内部环境中的任何变量和函数。每个环境都可以向上搜索作用域链以查询变量和函数名,但任何环境不能向下搜索作用域链。
扩展
有两个语句,可以使作用域链的前端增加一个变量对象:
catch和with;