前言
正确理解作用域链 ,执行上下文 ,对学习闭包知识 , this指向很有帮助
前置知识
首先问两个问题 , 切入今天的主题 : js 的执行上下文 !
- 为什么几乎所有的编程语言 , 代码都是从上往下执行的了 ?
- 又为什么所有的编程语言 , 在函数外都访问不到函数内的变量 ?
为了解决这些问题 , 我们首先需要了解
- js 执行上下文
- 作用链
js 的执行上下文是指 : 通俗的讲就是代码执行所处的当前容器。
作用域链是指在 JavaScript 中,用于查找变量和函数的机制所形成的一个链式结构。
补充 :上下文栈 是指 :通俗的理解就是 ,存放上下文 ”容器“ 的栈
后面会使用图片形象化这三个概念 !
我们从作用域的形成中挖掘出作用域与执行上下文的关系
- 当代码在一个执行上下文中运行时,JavaScript 会创建一个作用域链。作用域链的前端始终是当前执行上下文的变量对象。
- 对于函数作用域,变量对象包含函数的参数、局部变量和内部函数等。当在函数内部访问一个变量时,JavaScript 会首先在当前函数的变量对象中查找。
- 如果没有找到,就会沿着作用域链向上查找,也就是到包含该函数的外部函数的变量对象中查找。这个过程会一直持续,直到找到变量或者到达全局作用域的变量对象(全局对象)。
在 javaScript 中 , 大到整个浏览器再到一个函数,在到一个代码块都有自己的执行上下文 ,
js 在浏览器中的全局上下文是 window, 在 node 中的全局上下文是 global
对于全局上下文
- 会在你打开页面的时候创建 ,
- 在你退出页面 , 或者关闭页面的时候被销毁
同样每一个函数也有上下文 ,让我们来看看函数的执行上下文到底是怎么回事 ?
一段代码进入主题 -上下文栈
首先该函数在浏览器中运行 , 根据我们前面所说 , 会创建一个全局上下文 window, 且该全局上下文"容器"进入上下文栈 。
接着 ,函数也会形成一个上下文 , 也进入上下文栈 。
等函数执行往后 , 上下栈文会弹出该函数的上下文 ,将控制权还给之前的上下文,如下图
javaScript 的代码执行流就是通过这样的上下文栈来控制的 ,除此之外 , 代码在执行的过程中 ,还伴随着作用域链的创建 .作用链决定了上下文中的代码访问变量的顺序以及权限
一段代码直达底层
我们看看这段代码在浏览器中执行时 , 浏览器的底层会发生什么 ?
首先如果我们这段代码是在浏览器上运行的 , 那么浏览器就会创建一个全局上下文 windows , 并且将它推入到上下文栈之中 ,同时创建了一条作用域链 , 然后开始执行代码。(结合下图)
如果是在 node 上运行 , 就会创建一个全局上下文 global
开始执行代码 , 首先从上到下 , 执行到
- var color = "blue"
定义了一个 color 变量, 并赋值为"blue" , js 会将 color 变量创建到全局上下文的作用域链上
- function changeColor()
定义了一个 colorColor 变量 , 也会被创建到全局上下文的作用域链上。
之后代码执行了这个函数
- 第 11 行代码执行 changeColor() ,之后 js 的执行流进入函数内,changeColor 的执行上下文就被推倒栈顶 , 我们随着执行流进入函数
在函数内部定义了变量 anotherColor 变量 , 和函数 anotherColor() ,浏览器将这些变量在 changeColor 上下文中创建作用链, 如下图:
第九行执行了 swapColor() 函数 , 于是创建作用域链 ,并将 swapColor() 函数的上下文入栈,
于是我们随着执行流看去 , 在该函数的内部 ,进行的操作是交换两个变量的值 ,
一个变量是 tempColor, 这个是之前没有定义的 ,所以会在当前作用域形成作用域链 ,
那么对于 another color 和 color 呢 ? 他们不是当前函数 changeColor 的变量 , 他们为什么也可以在当前上下文中执行呢 ?
请往下看看 ~
这是 js 在访问变量的时候 , 会优先在当前上下文中寻找 , 如果找不到 , 会沿着作用域链寻找 ,一直找到全局作用域 ,如果到全局作用还没有 ,就输出 undefine , 很显然在该作用链中是可以找到的 ,这也就是为什么能够成功运行 !