JS做用域,做用域,做用链详解

前言html

  经过本文,你大概明白做用域,做用域链是什么,毕竟这也算JS中的基本概念。面试

一.做用域(scope)函数

  什么是做用域,你能够理解为你所声明变量的可用范围,我在某个范围内申明了一个变量,且这个变量能在这个范围内可用, 那么我能够说此范围就是该变量的做用域。post

  做用域通常分为局部做用域全局做用域。url

  怎么理解呢,先说局部做用域。假设我在A范围内用var申明了一个变量a,变量a只能在范围A内使用,超出A范围就调用不到,那么这样的变量a就是局部变量,范围A就是所说的局部做用域。spa

1 function A(){
2     var a = 1;
3     console.log(a);
4 }
5 A();//1
6 console.log(a);//报错,A未定义

  假设咱们在全局范围(没在任何函数体内)申明了变量b,你能够在任何局部做用域内去使用它,那么咱们通常称b为全局变量,包含b的范围就是全局做用域,b随处可用,没任何限制。.net

1 var b = 1;
2 function B(){
3     console.log(b);
4 }
5 B();//1
6 console.log(b);//1

  咱们在上面说,在A范围内用var申明变量a,a为局部变量,当咱们不用var申明时,即便在一个局部做用域内,它依旧属于全局变量。code

1 function A(){
2     a = 1;
3     console.log(a);
4 }
5 A();//1
6 console.log(a);//1

  只要一个变量申明前面未加任何申明符,那此变量就是全局变量,咱们不多这样去作,由于很难保证后期维护不会致使变量申明重名,这样的作法容易形成全局污染。htm

  顺带一提,在函数体内,局部变量的优先级高于同名的全局变量(函数形参也是局部变量),以下:blog

1 var a = 1;
2 function A(a){
3     console.log(a);
4 }
5 A(10);//10

  固然,函数的局部变量会被已存在的局部变量所覆盖:

1 function A(a){
2     var a = 1;
3     console.log(a);
4 }
5 A(10);//1

  有一点须要注意的是,咱们在实际开发中每每会遇到做用域嵌套,其实只要清楚做用域间变量是否能使用,是否会被覆盖的关系,就会很清晰了。

 1 var a = 1;
 2 function A(){
 3     var a = 2;
 4     function B(){
 5         var a = 3;
 6         console.log(a);
 7     }
 8     return B();
 9 }
10 A();//3

二.变量提高

  准确来讲,在ES6中新增的申明符let已经解决了变量提高这种不严谨的问题,我在这里简单提提,以前也有一篇博文是专门介绍变量提高的。

  什么是变量提高呢,就是说,一个变量在对应的做用域内是随处可见的,意思是,就算使用在前,申明在后,它依旧可以使用,不会报错。

  具体想了解看这篇文章吧--申明提早,变量申明提早,函数申明提早,申明提早的前后顺序

三.做用域链

  咱们在上面说,做用域也存在嵌套的问题,那么咱们能够这样去理解做用域链,当咱们须要某个变量的值时,咱们先去理它最近的做用域去找,若是找不套,就找它的上级做用域,依次类推,直到找到全局,若是全都未定义,那就抛出一个错误,以下。

1 var a = 1
2 function A(){
3     function B(){
4         console.log(a);
5     }
6     return B();
7 }
8 A();//1

  能够说,做用链的寻找过程是从内向外的过程,而不是从外到内,能够站在局部做用域去调用全局做用域的属性,反过来是不容许的。

 OK,概念大概说到这里吧,嗯,仍是来几道题目巩固下。

题目一

1 var a=10; 
2 function A(){ 
3  alert(a);
4 };            
5 function B(){
6  var a=20;
7  A();
8 }
9 B();//10

  为何输出10,而不是20?js中变量的做用域链与定义时的环境有关,与执行时无关。

  咱们调用函数B后,函数B又调用了函数A,函数A里面没定义变量a可是要用a,函数A只是被B调用且不传参,所以函数A无权使用函数B的局部变量a,而咱们在上方还有一个全局变量a,所以这里输出10.

1 var a=10; 
2 function A(a){ 
3   alert(a);
4 };            
5 function B(){
6   var a=20;
7   A(a);
8 }
9 B();//20

  这样就能够输出20了,函数B调用函数A的同时传入参数a,函数B提供了变量a,那就输出20了。

题目二

1 function aaa(){
2    a=10; 
3 }
4 alert(a);//报错

  想到了一个问题,这里就将题目稍做修改了。咱们在前面说,在局部做用域内,不用var 申明一个变量,它也是全局变量,随处可见,那为什么在外输出它会报错呢?

  函数是个很奇怪的东西,能够这样理解,一个函数当没被调用,它实际上是不可见的,它里面的全部变量也不可见,即便a确实是全局变量没错,它仍是在是否可见上受到了函数的限制,调用后就可见了。

1 function A(){
2    a=10; 
3 }
4 A()
5 alert(a);//10

  那咱们改为这样呢?

1 alert(a);//报错
2 function A(){
3    a=10; 
4 }
5 A();
6 alert(a)

  不是说函数调用后里面的变量a就随便用了吗,怎么上面的又报错了?由于代码都有本身的执行顺序,要知道第一次alert a,此时函数还未被调用,因此就报错了,有点绕,试着理解。

  就整理这么多吧,但愿有所帮助。

本文思路参考了 博文

JS做用域面试题总结

js做用域与原型的笔试题

相关文章
相关标签/搜索