前言
本文主要讲解JavaScript中作用域包括:什么是作用域,作用域种类、作用域作用以及作用域链的代码文字讲解。
什么是作用域?
在Js中,我们会定义大量的变量,如果在使用这些变量的过程中不及时清理,就可能造成内存泄漏或者内存阻塞的问题,那么解决这个问题的方案就是让每个变量都有一定的使用周期,在调用它们的时候被创造,调用结束后则消失,而这个创造消失的范围,就是作用域,作用域又被称为是某个变量的可见范围。具体可看下述代码:
<script>
let a=2;
function A(){
let a=1;
if(true){
let b=1
console.log(a,b);//1 1
}
console.log(b);//b is not defined
}
console.log(a);//2
A()
</script>
作用域种类:全局作用域、函数作用域以及块作用域。 在上述代码中,<script>就是一个全局作用域,而函数a则为函数作用域,if选择语句就是一个块级作用域。
我们首先定义了一个全局作用域下的a变量为2,然后定义了一个A函数,并在函数作用域下定义a变量为1,最后我们在if语句(块级)下定义了b变量为2,分别在块级作用域,函数作用域,全局作用域中打印a,b,会出现什么结果,首先在块级作用域中打印a,b,会出现1 1,因为b是块变量,而a=1是函数作用域下的变量,在if中,函数并没有结束,则可以调用到a变量,在函数作用域中我们打印b变量会出现报错信息b没有被定义,这是因为块级作用域已经结束了,所以块级作用域下的b也被js的内存机制清理掉了,并且在全局作用域中也没有b变量,所以打印出来b出现上述报错。最后在全局作用域中打印a出现2,也是因为函数作用域没被调用,即使被调用也会打印2,因为函数调用后会有结束,而结束的时候,就是函数作用域a变量被清理的时候,但全局变量只会在页面被关闭时才会被清理,所以我们要谨慎定义全局变量。
作用
- 封装变量与函数:可以将函数与变量进行封装,避免数据命名冲突,如上述函数作用域的a和全局作用域a并没有发生冲突,在函数中,全局作用域的a被函数作用域的a覆盖掉了。同时在函数外也无法调用函数作用域的a变量,这就保证了数据不会泄漏。
- 控制可访问性:确定了每个变量的可见范围,可以让变量在应该访问的时候被访问到。
- 支持闭包:作用域概念出现后,可以使用闭包来访问外部函数变量,也就是类似子函数的方式访问父函数。
作用域链
我们来根据代码来进行作用域链的讲解。
let a=1;
function A(){
return function(){
return a;
}
}
let demo=A()
console.log(demo());//1
上述代码引入了一个闭包的概念,当然这不是主题就不赘述了,闭包就是一个函数里面有一个子函数,我们现在只需要直到demo()是调用了A函数下的闭包函数,那为什么能取到全局变量a的值呢,就是因为作用域链,作用域链的概念就是指,当我们想要调用一个变量时,作用域会先从自身开始找这个变量,如果自身没有,则会往上一层作用域去找这个变量,如果上一层也没有,则会往再上一层去找,直到找到最顶层也就是全局作用域才会罢休,找到则返回,没找到则报错某变量没有被定义。
在上述代码中,return a是先找闭包函数中是否有这个a变量,没有,则找A函数作用域中是否有这个a变量,也没有,最后找到了全局作用域中是否有a变量,找到了,把这个a变量返回了。这就是作用域链的概念。