作用域与作用域链
作用域与作用域链
dleei什么是作用域和作用域链?
作用域(scope):简单来说作用域就是变量能够生效的一个范围,一旦超过了这个范围变量就无法访问
作用域链(Scope Chain):访问变量的一个查找过程,首先会在当前的作用域进行查找,查找不到就会返回到父级作用域来查找,若是依旧没有找到,就会依次逐级向上查找,直到全局作用域,变量访问的原则遵循就近原则
作用域的类型:
- 全局作用域
- 函数作用域
- 块级作用域
函数作用域
在foo
函数内声明了一个名字叫Jack ,在函数内访问打印,没有问题,但是在函数外无法访问到,name
变量的生效范围只有函数的{ } 内这么大一块的范围
1 | function foo() { |
块级作用域
块级作用域可通过ES6
新增命令let
和const
声明,所声明的变量在指定块的作用域外无法被访问。块级作用域在如下情况被创建:
- 在一个函数内部
- 在一个代码块(由一对花括号包裹)内部
1 | for(let i = 0;i<5;i++) { |
全局作用域
声明在<script>
标签和js
文件最外层的就是全局作用域,使用var
声明的变量也是属于全局作用域,无论在哪里都可以被访问到。
这里在全局声明了一个变量 a 赋值为了10,在全局和函数内都可以被访问到
1 | let a = 10 |
所有window
对象的属性拥有全局作用域
一般情况下,window
对象的内置属性都拥有全局作用域,例如window.name
、window.location
、window.top
等等。
全局作用域有个弊端:如果我们写了很多行 JS
代码,变量定义都没有用函数包括,那么它们就全部都在全局作用域中。这样就会 污染全局命名空间, 容易引起命名冲突。
值得注意的是若是变量没有声明直接进行赋值也属于全局变量,不推荐
1 | function foo() { |
为window
对象动态添加的属性默认也是属于全局的,同样不推荐
作用域链
1 | let foo = 'foo'; |
当函数fo()
被调用,Javascript
引擎首先在当前作用域下寻找变量bac
,然后寻找foo
变量但发现在当前作用域下找不到,然后继续在外部作用域寻找找到了它(这里是在全局作用域找到的)。
然后将42
赋值给变量number
。Javascript
引擎会在当前作用域以及外部作用域下一步步寻找number
变量(没找到)。
如果是在非严格模式下,引擎会创建一个number
的全局变量并把42
赋值给它。但如果是严格模式下就会报错了。
结论:当使用一个变量的时候,Javascript
引擎会循着作用域链一层一层往上找该变量,直到找到该变量为止。
小结
作用域:
- 作用域是指变量、函数和对象的可访问范围。
- JavaScript中的作用域分为全局作用域和局部作用域。
- 全局作用域中定义的变量可以在整个程序中访问,称为全局变量。
- 局部作用域由函数创建,在函数内部定义的变量只能在函数内部访问,称为局部变量或函数作用域变量。
作用域链:
- 作用域链是一种变量查找机制,用于确定在特定作用域中访问变量时的查找顺序。
- 当访问一个变量时,JavaScript引擎首先在当前作用域中查找该变量,如果找到了则直接使用。
- 如果在当前作用域中没有找到该变量,JavaScript引擎将会沿着作用域链向上一级作用域继续查找,直到找到该变量或者抵达全局作用域。
- 作用域链的尽头是全局作用域,如果在所有的嵌套作用域中都找不到该变量,JavaScript引擎将抛出
ReferenceError
。