js之作用域

    通过一天的学习,楼主总结了一下关于js基础中的作用域的一些知识点。废话不多说,直接来分析。
    首先请理解一下 什么是作用域?作用域你可以分开两部分来看,
    域:就是空间范围
    作用:就是读、写操作
    所以,作用域的意思就是在什么范围内你可以进行读和写的操作
    在深入了解作用域之前,我们还要研究一下浏览器,浏览器的内部有一段专门读取js的程序,我们给他起个名字叫做js解析器。下面我们了解一下这个解析器的工作方式。
    js解析器工作至少分为两个步骤
    1)准备工作,找一些东西,那么根据什么找呢?即根据 var function 参数这些东西找,例如变量: var a = 1 ,那么他就会找到变量a,注意,他只会找到声明的变量,而不会读取‘=’后面的东西,找到变量a后,js解析器提前给他赋了一个值undefined 。所以所有的变量在正式开始执行代码之前都会赋予一个值,这个值就是未定义。例如函数 function fn1(){alert(2);} 找到函数后给他什么值呢?函数里面一大堆,谁知道做什么呢,所以一上来找到的函数就是函数,即fn1=function fn1(){alert(2); },所以函数在正式执行代码之前都是整个函数块。
      我们整个把第一步的准备工作起个名字,就叫做JS预解析。


    2)逐行解读代码
       看一个小段代码:
       <script>
          alert(a);  //运行结果 undefined
          a = 1;
          alert(a);  //运行结果 1
       </script>
     分析:第一步已经找到了变量a,并赋值undefined,第二步读代码, 在读到第一个alert的时候,a是未定义,第二行的时候,通过表达式修改了变量a的值,a变成了1,所以弹第二个alert的时候,弹出的是1。好了,了解整个js解析器的工作方式后,我们来看几个小示例吧。


示例1:                     
<script>                   //标号1-9只为便于分析哪行代码 
 1.  alert(a);              //  function a(){alert(2);}
 2.  var a = 1;                                       
 3.  alert(a);              // 1
 4.  function a(){alert(1);}
 5.  alert(a);
 6.  var a = 2;
 7.  alert(a);
 8.  function a(){alert(2);}
 9.  alert(a);
</script>
分析:
 步骤1 预解析:
在2行找到变量a ,a=undefined  在第4行找到 函数 a=function a(){alert(1);}在预解析过程中,一旦遇到重名的,只会留下一个,那么留下哪个呢?一个是未定义,一个是函数块,那肯定是要留下函数块的。所以a=function a(){alert(1);},接着在第6行又找到变量a,那么肯定还是保留函数a的,再接着执行,执行到第8行,找到了和他级别相同的函数a,那么遵循上下级的关系,后面的函数a是后读到的,所以a变成了函数 a=function a(){alert(2);}
步骤2 逐行读代码
 第1行:弹出a 那么就会去仓库里面找a 发现a=function a(){alert(2);} 所以弹出function a(){alert(2);}
第2行:遇到表达式a=1,注意表达式是可以修改预解析的值,所以他就会无情的把a等于一个函数改变成a=1
第3行:弹出1
第4行:遇到函数,函数不是个表达式,所以不会修改a的值,所以a依旧等于1
第5行:弹出1
第6行:遇到表达式a=2,所以把a变成了 2
第7行:弹出2
第8行:不改变a的值
第9行:依旧是弹出 2;


示例2: 在script标签之间就是一个域,但是她是单线程的,所以会在一个script中预解析后逐行执行完再去下一个script标签
<script>
   alert(a);//执行结果会报错 a is not defined
</script>
<script>
   var a=1;
</script>


示例3:在第一个script标签内找到变量a,并赋值undefined 然后读代码,a的值变成了1,并且将a=1存到了大仓库中,所以在下一个script中可以找到变量a。由此我们可以总结出,在script中的全局变量,全局函数 是自上而下的,就是上面的东西会存下来,下面也能找的到。
<script>
  var a=1
</script>
<script>
    alert(a);//执行结果 1
</script>


示例4:函数也是一个作用域,里面的变量称之为局部变量,只要遇到域就会先预解析后执行,那么我们看看下面的代码执行的结果吧~
<script>
1. var a=1;                     
2. function fn1(){
3.    alert(a); //运行结果 undefined
4.    var a=2;
5. }
6. fn1();
7. alert(a);//运行结果 a=1;
</script>
1)预解析:
    找到变量 a a=undefined->a=1
    找到函数 fn1=function fn1(){alert(a);a=2};
         


2)执行代码:
    遇到表达式 变成a=1
    第6行的时候调动了函数fn1(),开启了一个局部作用域
          1)函数的作用域
              找到变量a ,a=undefined 
          2)逐行执行代码
              弹出undefined
              执行第4行,遇到表达式,将局部变量a的值修改成a=2
            
    执行第7行,弹出1 因为上次修改的2修改的是局部变量,而非全局变量a,所以在执行第7行的时候,找到的a是全局变量的a,即a=1;


示例5:
<script>
1. var a=1;                     
2. function fn1(){
3.    alert(a); //运行结果 1
4.    a=2;
5. }
6. fn1();
7. alert(a);//运行结果 a=2;
</script>
分析:首先找到全局的变量a,a=undefined,函数fn1()= function fn1(){
                                                   alert(a);
                                                   a=2;
                                                 }
     然后开始执行代码,表达式将a的值修改为1—>调用函数,开启局部作用域—>没有找到变量a,所以预解析结束,开始逐行读代码。这时候看到要弹出a,由于没有局部变量a,那么他就会顺着作用域链,由内向外的寻找变量a,并且在外面找到全局变量a,所以弹出1—>通过a=2表达式修改了全局变量的a,所以a=2—>开始执行第7行,这时候的a的值已经通过表达式修改成了2,所以弹出2;


示例6:
<script>
1. var a=1;                     
2. function fn1(a){
3.    alert(a); // 运行结果 undefined
4.    a=2;
5. }
6. fn1();
7. alert(a);// 运行结果1
</script>
分析:先解析全局变量a=undefined,函数fn1()= function fn1(a){
                                                   alert(a);
                                                   a=2;
                                                 }
开始读代码,1行执行后 a=1—>6行调用函数,开启新一个作用域,找到参数a,参数就相当于一个局部变量,所以局部作用域中a=undefined 所有3行执行结果为undefined,4行修改a=2—>7行执行弹出全局a,依然是1


示例7
<script>
1. var a=1;                     
2. function fn1(a){
3.    alert(a); // 运行结果 1
4.    a=2;
5. }
6. fn1(a);
7. alert(a);// 运行结果1
</script>
分析:先解析全局变量a=undefined,函数fn1()= function fn1(a){
                                                   alert(a);
                                                   a=2;
                                                 }
开始读代码,1行执行后 a=1—>6行调用函数并给了一个参数,开启新一个作用域,找到参数a,注意这时候的参数a接收传来的参数后,变成了var a=1;所以3行执行的结果是1,4行修改a=2—>执行7行找到的是全局a,所以弹出1。





评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值