• JavaScript基础学习--08 JS作用域


    一、浏览器
         1、“JS解析器”(至少分为两步骤)
              1.1     JS预解析(代码正式运行之前的准备工作)     “找一些东西并形成一个仓库”:var、function、参数
                   1.1.1     var a = 1;                                        找到var a = undefined     (所有的变量在正式运行代码之前,都提前赋值:未定义;--》undefined)
                   1.1.2     function fn(){ alert(......); }                  找到fn =  function fn(){ alert(......); }    (所有的函数在正式运行之前都是整个函数块)
                   1.1.3     预解析规则
                        1.1.3.1     遇到重名的:只留一个------变量和函数重名,选择留下函数;同等级的留下后面那个(两个变量重名留后者;两个函数重名留后者)
                        1.1.3.2     表达式可以修改仓库中的值     
                             1.1.3.2.1     表达式:+-*/ Number()......     注意:函数只是一个声明,不是表达式
     
              1.2     逐行解读代码
     1 alert(a);   // function a(){alert(4);}
     2 var a = 1;  // 表达式能改变仓库中(预解析仓库)的值---> a = 1
     3 alert(a);   // 1
     4  
     5 function a() {  //函数声明不是表达式,不能改变a的值
     6     alert(2);
     7 }
     8 alert(a);   // 1
     9 var a = 3;  //  表达式能改变仓库中(预解析仓库)的值---> a = 3
    10 alert(a);   // 3
    11  
    12 function a() {  //函数声明不是表达式,不能改变a的值
    13     alert(4);
    14 }
    15 alert(a);   // 3
    16  
    17 a();     //a is not a function 报错,因为此时仓库中已经没有函数a了
    18  
    19  
    20       
    21 模拟浏览器解析:
    22 预解析:
    23 a = undefined
    24 a = function a(){alert(2);}
    25 a = undefined
    26 a = function a(){alert(4);}
    27 综上,最后 a = function a(){alert(4);}
    28 所以 ......
         
    二、作用域     只要是一个域,就会发生预解析。其中script标签是一个域
         1、每个script标签代表一个域块,从上到下的顺序,执行完一个script块中 js(预解析+逐行读代码) 才执行下一个script(如果有的话)
         2、script是全局变量、全局函数
         3、函数也是一个域,所以遇到函数执行时也会发生至少两步骤:预解析+逐行读代码     读代码:由里而外,作用域链
         4、{} 也是一个域,所以遇到 {} 执行时也会发生至少两步骤:预解析+逐行读代码
     1 var a = 1;  // a = 1
     2 function fn(){  //fn不变
     3     alert(a);   //  // undefined
     4     var a = 2;  //  // a = 2
     5 }
     6 fn();   // // 开始fn的预解析+逐行读代码
     7 alert(a);   //完成fn代码域的js解析,这是全局下的a ---> // 1
     8  
     9 模拟浏览器解析:
    10 预解析:
    11     a = undefined
    12     fn = function fn(){alert(a); var a = 2;}
    13 综上:读代码 //
    14  
    15 fn 中的预解析:
    16     a = undefined
    17 综上:读代码 // //
     
    1 var a = 1; // a = 1
    2 function fn() { //fn不变
    3     alert(a); //  // 预解析的仓库中没有,此时作用域链发生作用,由里而外,局部没有,找全局中a = 1
    4     a = 2; //  // a = 2
    5 }
    6 fn(); // // 开始fn的预解析+逐行读代码
    7 alert(a); //完成fn代码域的js解析,这是全局下的a,并且被局部函数中的表达式改变了值 ---> // 2
    模拟浏览器解析:
    预解析:
    a = undefined
    fn = function fn() { alert(a); var a = 2; }
    综上: 读代码 //
     
    fn 中的预解析:
    仓库为空
    综上: 读代码 // //
     1 var a = 1; // a = 1
     2 function fn(a) { //fn不变
     3     alert(a); //  // 预解析仓库中有,就优先预解析仓库的值---> undefined
     4     a = 2; //  // a = 2 修改的是仓库中的a,没有修改全局的 a
     5 }
     6 fn(); // // 开始fn的预解析+逐行读代码
     7 alert(a); //全局中的a  1
     8  
     9  
    10  
    11 模拟浏览器解析:
    12 预解析:
    13 a = undefined
    14 fn = function fn(a) { alert(a); var a = 2; }
    15 综上: 读代码 //
    16  
    17 fn 中的预解析:
    18 a = undefined //这是参数a,也是被预解析的对象
    19 综上: 读代码 // //
     1 var a = 1; // a = 1
     2 function fn(a) { //fn不变
     3     alert(a); //  // 预解析仓库中有,并且传值a = 1(fn(a) == fn(var a = 实参a<如果有传参的话>))就优先预解析仓库的值---> 1
     4     a = 2; //  // a = 2 修改的是仓库中的a,没有修改全局的 a
     5 }
     6 fn(a); // // 开始fn的预解析+逐行读代码
     7 alert(a); //全局中的a  1
     8  
     9 模拟浏览器解析:
    10 预解析:
    11 a = undefined
    12 fn = function fn(a) {alert(a);var a = 2;}
    13 综上: 读代码 //
    14  
    15 fn 中的预解析:
    16 a = undefined //这是参数a,也是被预解析的对象
    17 综上: 读代码 // //
    为了防止预解析浏览器兼容:尽量不要在if、for中定义函数、定义变量等等
    1 alert(fn);  //预解析中if、for不是一个作用域,所以里面的变量相当于全局变量,所以弹出function fn(){alert(2);}
    2             //但是,在FF浏览器中有兼容性,会报错,fn未定义!!!
    3 if(true){
    4     function fn(){
    5         alert(2);
    6     }
    7 }
     
    注意:for循环内部的函数与i
     1 for (var i = 0; i < 3; i++) {
     2     oBtn.onclick = function() {
     3         alert(i); //undefined     原因是函数内部是一个域,内部找到var i---> i预加载是undefined
     4         for (var i = 0; i < 3; i++) {
     5             ......
     6         }
     7     }
     8 }
     9  
    10 for (var i = 0; i < 3; i++) {
    11     oBtn.onclick = function() {
    12         alert(i); //3     原因是函数内部是一个域,预加载时没有变量,于是第二部在逐行读代码的时候找不到i,到作用域链上(外部)找到i = 3,所以3
    13         // for (var i = 0; i < 3; i++) {
    14         //     ......
    15         // }
    16     }
    17 }
    18  
    19 for (var i = 0; i < 3; i++) {
    20     oBtn.onclick = function() {
    21         alert(i); //3      原因是函数内部是一个域,预加载时没有变量,于是第二部在逐行读代码的时候找不到i,到作用域链上(外部)找到i = 3,所以3
    22         for (i = 0; i < 3; i++) {
    23             ......
    24         }
    25     }
    26 }
  • 相关阅读:
    bzoj3224 普通平衡树
    bzoj 1067 分情况讨论
    bzoj 1269 bzoj 1507 Splay处理文本信息
    bzoj 2733 Splay 启发式合并,名次树
    bzoj1502 simpson求面积
    b_lq_晚会界面单(线段树维护区间最大值表+预留m个位置)
    a_lc_统计子树中城市之间最大距离(枚举子集 + floyd / 2*dfs 求直径)
    b_lq_城市建设 & 公路修建水题 & 新的开始(虚拟结点+MST)
    b_lg_无线通讯网 & 北极通讯网络(问题转化+kruskal)
    b_lg_搭配购买(并查集+01背包)
  • 原文地址:https://www.cnblogs.com/hihao/p/7344684.html
Copyright © 2020-2023  润新知