前言
最近看到阮一峰老师写的技术写作的首要诀窍,其中的内容令我深受启发
阮一峰老师在文中首先强调了技术写作的好坏,跟语文水平关系不大,更多是一个技巧问题。优秀的技术文章需要表达清楚明白、让读者快速轻松学会文章中内容。所以笔者本人觉得
一篇技术文章的内容不需要包罗万象,容易贪多嚼不烂,倾向选取一个小知识点,从头到尾采用平铺直叙的方式将知识点讲清楚、讲明白
由此笔者打算在本篇博客尝试这样的写作方式。前端调试一直是前端中非常重要的内容,涉及解释器、runtime、调试工具和调试原理等等内容,这里面可以写很多篇技术文章。
本篇文章只讲一讲使用 Chrome DevTools 调试工具在浏览器中如何使用 Scope 面板
什么是作用域?
在 JavaScript 中,作用域(Scope)是指变量和函数在程序中可见和可访问的范围。作用域决定了变量和函数的生命周期,以及它们的可见性。JS 只有静态作用域,所以 JS 的作用域与函数定义时的位置有关、与函数调用位置无关,函数嵌套会形成长长的作用域链
Scope 分类
上面说的作用域的定义,那么 JS 中有那些作用域呢,由于 JS 中的不断发展,JS 中的作用域越来越多,目前 Scope 主要分为下面六类:
- Block:代码中由 let 和 const 声明的块作用域(Block Scope)中的变量
- Local:当前函数作用域内声明的变量
- Closure:外层函数内声明的变量
- Module:Module 文件中的声明的变量
- Script:以 const、let 声明的变量
- Global:以 var 声明的变量或者挂载在 window 对象上的属性
以下面的程序代码为例,暂停在console.log
时,a、b、c、d、e 变量正好属于五种不同的作用域
// index.mjs
var a = "a";
let b = "b";
const c = "c";
function outer() {
let d = "d";
function inner() {
let e = "e";
if (true) {
let f = "f";
console.log(a, b, c, d, e, f);
}
}
inner();
}
outer();
如图所示,Module 文件的 Scope 如图所示
从上图可以看出,程序代码出现五种 Scope,实际上对于支持 ES Module 的文件在浏览器中解析执行时叫 Module Scope,当普通的 JS 文件在浏览器中解析执行叫 Script Scope
下面详细讲解这些 Scope
Block
块作用域(Block Scope)是一种变量作用域的规则,主要与变量在代码块中的可见性和生命周期相关。块作用域的基本概念是,变量的作用范围仅限于其所在的代码块中。这种作用域通常由大括号 {}
来定义,如在函数、条件语句或循环中
用大白话讲,使用 const 或 let 关键字声明变量,那么 {} 则形成块作用域,变量的作用范围仅限于其所在{}中
请看下面的示例代码。在条件语句中的 Block Scope
if (true) {
let a = "a";
console.log(a); // 只能在这里访问到a
}
console.log(a); // ReferenceError: a is not defined
将断点选在第四行的位置,在浏览器中会出现下面的效果
此时,Scope 面板中只有两类 Scope,对于任何的 JS 代码,Global Scope 是必定存在的,时作为兜底的 Scope,然后是 Block Scope,通过 Block Scope 可以查看当前的 Block Scope里有哪些变量
在循环语句中的 Block Scope
for (let index = 0; index < 3; index++) {
console.log(index);
}
将断点运行在第二行的位置,在浏览器中出现下面的效果
最后特别说明一下在函数体中使用 const 和 let 声明变量的效果
根据块作用域的定义使用 const 或 let 关键字声明变量,那么 {} 则形成块作用域,在函数体中使用 const 和 let 声明变量也会产生块作用域
function foo() {
let a = "a";
console.log(a);
}
foo()
但是函数本身有函数作用域,所以在在函数体中使用 const 和 let 声明变量,函数作用域即是块作用域,块作用域也是函数作用域
Local
Local Scope 是指变量、函数或其他标识符仅在某个特定代码块或函数内可访问的范围。局部作用域的作用是将变量限定在特定的范围内,防止它们在外部代码中被误用或修改。这样可以提高代码的封装性,避免命名冲突,并使代码更加易于理解和维护
请看如下的示例代码
function outer() {
const b = "b";
function inner() {
const a = "a";
console.log(a, b);
}
inner();
}
outer();
在 console.log 加上断点,重新运行后,可以看到如下效果
Closure
虽然名字叫Closure,但是没有闭包作用域概念,Closure Scope是指当前Local Scope的作用域的外层函数。
在Local中的示例代码上,外层函数是 outer
方法
Module
Module Scope(模块作用域)指的是在模块化编程中,一个模块内部的作用域。模块作用域使得模块内定义的变量、函数或类在模块外部不可直接访问,形成了一种封闭的作用域。
请看下面的示例代码
<script type='module'>
const a = 'a'
console.log(a)
</script>
在浏览器中的运行效果如下所示
<script type="module"></script>
是 HTML5 引入的一种用于在浏览器中使用 JavaScript 模块(ES6 模块)的方式。通过设置 type="module"
,在浏览器中直接使用 ES6 的模块化特性,例如 import
和 export
在console.log
的行号槽加上断点,重新执行后,可以在Scope面板中看到变量a
属于Module Scope
Script
Script Scope指使用<script>
标签中声明的变量。请看如下代码示例
只需要将 Module 中的示例代码删除 type='module'
<script>
const a = 'a'
console.log(a)
</script>
在浏览器中的运行效果如下所示
在console.log
的行号槽加上断点,重新执行后,可以在Scope面板中看到变量a
属于Script Scope
Global
Global Scope(全局作用域)指的是在程序中最外层的作用域范围。任何在全局作用域中声明的变量或函数,都可以在整个程序的任何地方被访问和使用