持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第23天,点击查看活动详情
前言
😀 面试中,作用域的问题是最常见的,不论是初级、中级、还是高级,只要你是做前端的,基本都会问这个问题。
😀 而作用域是前端编程语言中最基本的功能,它能够存储变量当中的值,并且可以在之后的逻辑中对这个值进行访问和修改。
😀 但是将这个作用域中的变量引入到代码中,就会发生一些神奇的事情,这也是这篇文章中会带你理解的部分。
词法作用域
😉 词法作用域就是定义在词法阶段的作用域。你也可以理解为你在写代码的时候,将变量和块作用域写在哪里就觉得了词法作用域在哪里。
function foo(a){
var b = a * 2;
function bar(c){
console.log(a, b, c)
}
bar(b * 3);
}
foo(2);
🤪 上面这段代码,我们不需要理解输出的结果是什么,我们只需要理解其中的作用域关系即可。
foo函数包含着整个全局作用域。a、 bar、 b包含在foo函数所创建的作用域中。c包含在bar函数所创建的作用域中。
为了便于理解,可以将上面这段代码想象成几个逐级包含的气泡。
也就是这些作用域气泡由其对应的作用域块代码写在哪里决定的。
- 当代码在支持 console.log() 时,它需要查找 a、b、c 三个变量的引用
- 查找的过程就是逐层往外去寻找,找到了就使用这个引用关系
作用域查找会在找到第一个匹配的标识符时停止。
无论函数在哪里被调用、如何调用,它的词法作用域都只由函数被声明时所处的位置决定。
eval函数
在JavaScript词法作用域中,由于它是在写代码期间被函数的声明位置定义的,那么怎么才能在运行的过程中去修改词法作用域呢?
😷 先看代码,再来分析
function foo(str, a){
eval(str);
console.log('输出:', a, b);
}
var b = 1;
foo('var b = 2', 0);
- 这里输出的是 0 和 2
- 但是我们定义的全局变量 b 的值是 1 ,为什么会变成 2 呢?
😌 这是因为 eval 函数虽然接收的是一个字符串,但是它并不会将它视为一段字符串,而是视为书写时就存在于程序中的一段代码,然后放置在 eval 函数执行的位置。
😌 也正是因为 eval 函数通过欺骗的方式来实现修改词法作用域
总结
在JavaScript的词法作用域中的作用域是由书写代码时函数声明的位置来决定的,编译过程中,可以使用 eval 函数来修改其中声明的某个作用域。
在使用 eval 函数时,也会导致代码运行变慢,所以最好是不要使用它。