今天咱们来用介绍一下 JS 中的做用域链,先来看一段代码:javascript
const name = "Lydia" const age = 21 const city = "San Francisco" function getPersonInfo() { const name = "Sarah" const age = 22 return `${name} is ${age} and lives in ${city}` } console.log(getPersonInfo())
上面调用了函数 getPersonInfo
,而后返回了一个包含 name
,age
,city
的字符串:java
Sarah is 22 and lives in San Francisco
。segmentfault
可是 getPersonInfo
这个函数中并无 city
变量,那么它是怎么访问到 city
的呢?浏览器
首先,不一样的执行上下文会分配不一样的内存空间。咱们有默认的全局上下文(浏览器中是 window
,Node 中是 global
),函数 getPersonInfo
在被调用时也会建立一个 本地上下文。每一个执行上下文都有一个 做用域(链)。函数
对于函数 getPersonInfo
,它的做用域链就像下图这样:oop
做用域链基本上是对 对象(即上图中的 activation object 和 global object)的 “引用链”,这些对象中包含了对该执行上下文中 可引用的变量及其余做用域 的引用。而且,做用域链是在执行上下文被建立的时候建立的,即这一切发生在 运行时。spa
简单来讲,做用域(链)里面存储着执行上下文须要访问的变量。翻译
然而,本篇先不讲 activation object 或者 执行上下文,咱们先把注意力放在 做用域(链) 上!
在下图的例子中,执行上下文中的键值对即表明了做用域链对变量的引用。code
全局执行上下文中有三个变量:对象
本地执行上下文中有两个变量:
当咱们在函数 getPersonInfo
中试图访问变量时,JS 引擎会首先检查本地做用域链。
本地做用域链能够访问到 name
和 age
,它们的值分别是 Sarah
和 22
。可是当须要访问 city
时会发生什么呢?
为了访问 city
变量,JS 引擎会 顺着做用域链查找。能够说 JS 引擎是个耿直 boy,你提的要求他不会轻易放弃,他会沿着做用域链一直找 city
变量,直到找到顶层 global object
位置。
在全局做用域,因为咱们定义了 city
的值为 San Francisco
。因此函数拿到了这个值,而且打印出了 Sarah is 22 and lives in San Francisco
。
咱们说顺着做用域链查找,可能说向上和向下都有歧义,那么就统一更正为向 外层 做用域查找好了!看下面的 3D 图:
或者更多层的话:
咱们再来看最开始的例子:
上图和最开始的例子几乎是同样的,只不过把 city
定义在了函数 getPersonInfo
中。咱们尚未调用函数 getPersonInfo
,因此本地做用域也没有建立。那么当咱们在全局做用域中访问 name
、age
和 city
时:
程序抛出 ReferenceError
!由于在全局做用域中找不到变量 city
,而且已经没有再外层的做用域了,即无法顺着做用域链找下去。
除了全局做用域和本地做用域,还有一个是 块级做用域,当咱们在花括号 { }
中用 let
或者 const
关键字定义变量时,就产生了块级做用域。
const age = 21 function checkAge() { if (age < 21) { const message = "You cannot drink!" return message } else { const message = "You can drink!" return message } }
用虚线表示做用域以下:
咱们有一个全局做用域、一个函数做用域和两个块级做用域。也正是因为块级做用域的存在,因此咱们能定义 message
两次。
咱们来回顾一下:
本篇就到这里啦,本文是翻译的系列文章:
本文首发于公众号:码力全开(codingonfire)
欢迎关注获取最新内容哦~