# 图解javascript作用域

本文原文地址 (opens new window)

此文章是回答知乎问题总结而来 (opens new window)

# 作用域访问规则

let count = 0;

function func() {
  console.log(count);
}

func();
1
2
3
4
5
6
7

下面我们来看看变量count是如何被打印出来:

1. `func`函数调用,`console.log`打印`count`变量,查找当前函数作用域,是否存在变量`count`;
2. 不存在继续向上查找,查找模块作用域,发现`count`变量存在,并且打印出变量的值。

如果模块作用域依然不存在count变量?

会继续向上查找,查找全局作用域是否存在count变量,如果依然不存在,提示undefined

如下图所示:

通过上面的示例代码,我们可以知道一个规则,作用域访问顺序:函数作用域 ——> 模块作用域 ——> 全局作用域

提示:作用域访问的方向是不可逆只有由里向外访问,先函数,再模块,最后全局;

# 作用域创建规则

JavaScript中的作用域是词法作用域(相对于动态作用域)。

什么叫词法作用域?顾名思义,词法作用域就是定义在词法阶段的作用域。换句话说,词法作用域是由你在写代码时将变量和块作用域写在哪来决定的。

无论函数在哪里被调用,也无论它如何被调用,它的词法作用域都只由函数被声明时所处的位置决定,这就是JavaScript的词法作用域。(除非你使用 with (opens new window) 或者 eval (opens new window) 欺骗它) 我们来看下面的例子:

let count = 0;

function func(name) {
  console.log(count, name);
}

func('func');
1
2
3
4
5
6
7

代码执行,作用域创建顺序:

1. 优先创建全局作用域,如全局window对象,或者挂载在全局的函数或属性;
2. 之后模块作用域被创建,`count`变量会挂载在模块作用域,`func`函数也是挂载在模块作用域;
3. 最后才是函数作用域,此时全局作用域和模块作用域已创建生成,如果它需要使用外部的存在的变量或方法,只需向上查找即可;

如下图所示:

上图中作用域创建是至上而下,我省略了表示递进关系的线条。我们来归纳一下,作用域创建顺序是:全局作用域 ——> 模块作用域 ——> 函数作用域

在调用完成之后,作用域也会相应释放。如果是存在闭包,作用域链就会被保存,可以看看:闭包装逼失败(闭包使用) - 掘金 (opens new window)

# 总结

  • 作用域访问顺序:函数作用域 ——> 模块作用域 ——> 全局作用域
  • 作用域访问的方向是不可逆只有由里向外访问
  • 作用域创建顺序是:全局作用域 ——> 模块作用域 ——> 函数作用域

以上内容希望可以帮助到你,你的点赞、收藏是我更新的动力!!

# 参考

MDN文档

《你不知道的Javascript上卷》

冴羽 · JavaScript深入之执行上下文 (opens new window)

🥰Me

男性,武汉工作,会点Web,擅长Javascript.

技术或工作问题交流,可联系微信:1169170165.

🚀小程序&公众号
🚀运行
2024年2月19日星期一下午2点01分
博客已运行:--天--时--分--秒
上次更新: 7/18/2023, 11:23:11 AM

评 论: