js作用域(變數提升,預解析)例題

GoodLiang發表於2018-03-10

典型例題如下:

<script>
  alert(a)   // function
  a()    //10
  var a=3;
  function a() {
    alert(10)
  }
  alert(a) //3
  a=6;
  a()  // 沒有a這個函式了啊
</script>
複製程式碼

為什麼會有這樣的結果呢?請看下面的例題

例題一

<script>
  /*1
  alert(a); //underfined(未定義)
  var a=1;
  */

  /*2
  alert(a)
  a=1; //報錯,a is not defined
  */
  
  /*
  
  js解析器
  1.“找一些東西”(js預解析)var function 引數
   根據var找到; a=未定義,所有的變數在正式執行前都提前都賦值了未定義
   fn1=function fn1() {alert(2)}
   所有的函式,在正式執行程式碼之前,都是整個函式快
  2.逐行解讀程式碼
    表示式:= + - * 、/ % ++ --! 引數 .......

   alert(a)
   var a=1;
   function fn1() {alert(2)}
   
   */
</script>

複製程式碼

例題二

<script>
  /*
  js預解析只會留下一個,!!!變數和函式重名了,只留下函式 
  第一步:
  a=未定義
  a=function a() {alert(2)},那麼上面的那個就被幹掉了;
  最後,在預解析倉庫裡面只有:
   a=function a() {alert(4)}
   */

  //開始逐行解讀
  alert(a);//function a() {alert(4)}
  var a=1;//表示式:a就被改成1了;
  alert(a)//1
  function a() {alert(2)}//是函式宣告,不是表示式,不會改變a的值
  alert(a);//1
  var a=3;
  alert(a);//3
  function a() {alert(4)};
  alert(a);//3

  a()//報錯,讀完程式碼之後,js倉庫裡面只有a=3;
</script>

複製程式碼

例題三

<!--<script>-->
    <!--//1.預解析-->
    <!--//2.執行-->
<!--</script>-->

<!--<script>-->
    <!--//3.預解析-->
    <!--//4.執行-->
<!--</script>-->

 <!--
 1.
  <script>
    var a=3;
  </script>

  <script>
    alert(a);//3
  </script>
 -->

  <!--
  2. <script>
      alert(a);//報錯;a is not defined
    </script>

    <script>
      var a=3;
    </script>

  -->

複製程式碼

例題四

<script>
  var a=1;
  function fn1() {
    alert(a);//undefined
    var a=2;
  }
  fn1();
  alert(a);//1
  /*
  1.預解析
  全域性的   a=未定義
  fn1=function fn1() {alert(a);var a=2;}
  2.逐行解讀程式碼:
  表示式 a=1;
  函式呼叫
    1)預解析
    區域性的   a =未定義

    2)逐行解讀程式碼
    alert(a)=>未定義
          a=2;
   */
</script>

複製程式碼

例題4-1

<script>
  var a=1;
  function fn1() {
    alert(a);//1
     a=2;
  }
  fn1();
  alert(a);//2
  /*
  1.預解析
  全域性的   a=未定義
  fn1=function fn1() {alert(a); a=2;}
  2.逐行解讀程式碼:
  表示式 a=1;
  函式呼叫
    1)預解析
    順著這一層的作用域跳到上一層去找(作用域鏈)

    2)逐行解讀程式碼
    alert(a)//當前作用域沒有,順著這一層的作用域跳到上一層去找(作用域鏈)
    a=2也是
    先彈出1,再彈出2
   */
</script>

複製程式碼

例題4-2

<script>
  var a=1;
  function fn1(a) {//引數相當於是一個區域性變數   相當於括號裡面是var a;
    alert(a);//undefined
     a=2;
  }
  fn1();
  alert(a);//1
  /*
  1.預解析
     a=未定義
  fn1=function fn1(a) {alert(a); a=2;}
  2.逐行解讀程式碼:
  表示式 a=1;
  函式呼叫
    1)預解析
    裡面的a=未定義

    2)逐行解讀程式碼
          裡面的a=2;
   */
</script>

複製程式碼

例題4-3

<script>
  var a=1;//標誌1
  function fn1(a) {//引數相當於是一個區域性變數   相當於括號裡面是var a;
    alert(a);//1,這個a和標誌1處的a是不相同的,這個a是區域性的,外面的a是全域性的
    a=2;
    alert(a)//2
  }
  fn1(a);//這個a是全域性
  alert(a);//1
  /*
  1.預解析
     a=未定義
  fn1=function fn1(a) {alert(a); a=2;}
  2.逐行解讀程式碼:
  表示式 a=1;
  函式呼叫
    1)預解析
    裡面的a=未定義

    2)逐行解讀程式碼
          讀到fn1(a)的時候  就function fn1(var a=1)
          找到區域性的a=2
   */
</script>

複製程式碼

例題4-4


<script>
  var a=1;
  function fn1(a) {       //相當於var a;a=1(外面的)
    alert(a);//1
     var a=2;
     console.log(a);//2
  }
  fn1(a);
  alert(a);//1
</script>

複製程式碼

例題4-5

<script>
  var a=1;
  function fn1(a) { 
    arguments[0]=3;
    alert(a);//3
    var a=2;
    console.log(a);//2
  }
  fn1(a);
  alert(a);//1
</script>

複製程式碼

例題5 想要獲取函式內的值

<script>
  //想要獲取函式內的值
  // 一
  /*
  var str=''
  function fn1() {
    var a='1';
    str=a;
  }
  fn1();
  alert(str)
  */
  // 二
  function fn2() {
    var a='100元';
    fn3(a);
  }
  fn2()
  function fn3(b) {
    alert(b)
  }
</script>

複製程式碼

例題6

<script>
  /*
  函式的大括號才是一個域
  if條件判斷的大括號不是一個作用域,var 寫在大括號裡面和外面是一樣的
   if(1){
   var a=1;
   }
   alert(a);
   for 迴圈的{}也不是一個塊級作用域

  是作用域的標誌是先解析後執行
   */


  /*
  alert(a);//undefined
  if(true){
    var a=1;
  }*/

  /*
  alert( fn1 );//underfine(最新的瀏覽器),ie10及以下是可以彈出函式的。。。
  if(true){
    var a=1;
    function fn1() {
      alert(123)
    }
  }*/


  /*
  //所以,以上程式碼要寫成
  alert( fn1 );
  var a=1;
  function fn1() {
    alert(123)
  }
  if(true){

  }*/
</script>

複製程式碼

例題7

<body>
  <input type="button" value="1">
  <input type="button" value="2">
  <input type="button" value="3">
  <script>
    /*
    //1.
    window.onload=function () {
      var oBtn=document.getElementsByTagName('input');
      for(var i=0;i<oBtn.length;i++){
        oBtn[i].onclick=function () {
          console.log(i);//3
        }
      }
    }*/

    
/*     //2
    window.onload=function () {
      var oBtn=document.getElementsByTagName('input');
      for(var i=0;i<oBtn.length;i++){
        oBtn[i].onclick=function () {
          console.log(i);//undefined     因為函式域解析了,來自下面for的var i;
          for(var i=0;i<oBtn.length;i++){
            oBtn[i].style.background='yellow'
          }
        }
      }
    } */




  </script>
</body>

複製程式碼

相關文章