图解javascript作用域
作用域访问规则
let count = 0;
function func() {
console.log(count);
}
func();
下面我们来看看变量count
是如何被打印出来:
1. `func`函数调用,`console.log`打印`count`变量,查找当前函数作用域,是否存在变量`count`;
2. 不存在继续向上查找,查找模块作用域,发现`count`变量存在,并且打印出变量的值。
如果模块作用域依然不存在count
变量?
会继续向上查找,查找全局作用域是否存在count
变量,如果依然不存在,提示undefined
。
如下图所示:
通过上面的示例代码,我们可以知道一个规则,作用域访问顺序:函数作用域 ——> 模块作用域 ——> 全局作用域
提示:作用域访问的方向是不可逆,只有由里向外访问,先函数,再模块,最后全局;
作用域创建规则
JavaScript中的作用域是词法作用域(相对于动态作用域)。
什么叫词法作用域?顾名思义,词法作用域就是定义在词法阶段的作用域。换句话说,词法作用域是由你在写代码时将变量和块作用域写在哪来决定的。
无论函数在哪里被调用,也无论它如何被调用,它的词法作用域都只由函数被声明时所处的位置决定,这就是JavaScript的词法作用域。(除非你使用 with 或者 eval 欺骗它)
我们来看下面的例子:
let count = 0;
function func(name) {
console.log(count, name);
}
func('func');
代码执行,作用域创建顺序:
1. 优先创建全局作用域,如全局window对象,或者挂载在全局的函数或属性;
2. 之后模块作用域被创建,`count`变量会挂载在模块作用域,`func`函数也是挂载在模块作用域;
3. 最后才是函数作用域,此时全局作用域和模块作用域已创建生成,如果它需要使用外部的存在的变量或方法,只需向上查找即可;
如下图所示:
上图中作用域创建是至上而下,我省略了表示递进关系的线条。我们来归纳一下,作用域创建顺序是:全局作用域 ——> 模块作用域 ——> 函数作用域
在调用完成之后,作用域也会相应释放。如果是存在闭包,作用域链就会被保存,可以看看:闭包装逼失败(闭包使用) - 掘金。
总结
- 作用域访问顺序:函数作用域 ——> 模块作用域 ——> 全局作用域
- 作用域访问的方向是不可逆,只有由里向外访问
- 作用域创建顺序是:全局作用域 ——> 模块作用域 ——> 函数作用域
以上内容希望可以帮助到你,你的点赞、收藏是我更新的动力!!
参考
MDN文档
《你不知道的Javascript上卷》
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。