javascript--12---作用域

作用域

  1. 什麼是作用域
  • 作用: 對代碼的一個讀寫操作
  • 域:空間 範圍 js能實現的一個範圍
<script>
    console.log(a);
    var a =1;
  
</script>

結果是undefined
沒有聲明爲什麼會報undefined? 首先預解析 找到a 爲undefined 執行代碼 =改變變量的值 但是console在等號之前 所以結果是 undefined

<script>
    a =1;
    console.log(a);
</script>

爲什麼沒有聲明卻能打印出1?

  • 如果 在script沒有聲明 直接賦值 也能行
<script>
    console.log(a);
    a =1;
</script>

直接報錯
爲啥是報錯? 預解析 沒找到a 沒有var 在console.log之前 既沒有聲明 也沒有賦值 所以報錯 後面的a=1相當於沒有

<script>
   var a=1;
   console.log(window.a);
</script>

結果是1 window是script標籤中最大的一個對象

  • 平時在script 中var的時候 其實是在最大的window上加了一個屬性
<script>
   a=1;
   console.log(window.a);
</script>

結果是1

  • 沒有var也會自動在window上加一個屬性 這是系統在找不到聲明的時候 自動加的

解釋器

js是一種直譯式腳本語言

  1. 解釋器:在瀏覽器內核中有一個解釋器 看到script標籤 就直接擼起袖子幹 沒有長期的準備
  2. 解釋器在讀取js代碼的時候 也至少分爲兩步
  • 找一些東西 根據關鍵字 去查找 var(變量聲明) function(函數聲明) 參數
    找到變量聲明之後 不去讀取賦值 而是直接給一個undefined值

    找到函數聲明之後不會執行函數  而是把函數的內容當作一塊直接存起來
      比如  a:function(){}
  • 解釋代碼 先找到我們的 預解析找到的變量 如果有能改變變量值的運算:+ — ++ -- */% 修改了這個先找到的undefined/function(){}

<script>
   alert(a);//結果是function a(){alert(3)}
   var a=1;
   alert(a);//結果是1
   function a() {
       alert(2);
   }
   alert(a);//結果是1
   var a=3;
   alert(a);//結果是3
   function a() {
       alert(3);
   }
   alert(a);//結果是3
   a();//報錯
</script>
  1. 預解析
  • a :undefined 如果預解析過程中 函數名和變量重名了 函數會把變量無情覆蓋
  • a :function{alert(2)}
  • 如果預解析中 有重名函數 後者會把前者覆蓋
  • a :function{alert(3)}
  1. 執行階段
  • 第一個alert 結果是打印函數體function{alert(3)}
  • 修改a=1,第二個alert 結果是打印1
  • function只在預解析會用到 跳過function 第三個alert 結果是打印1
  • 修改a=3,第四個alert 結果是打印3
  • 跳過function 第五個alert 結果是打印3
  • a=3 3();是啥哦 會報錯

全局作用域 和 局部作用域

全局作用域

  1. 最大的作用域是 script標籤之間 全局中最大的對象是 window window是最大的作用域 但是script是分別解釋的 代碼自上而下執行 script全部解讀完之後 window還是最大的對象 在引入代碼的時候一定要注意引入順序 因爲script是分別解釋的
<script>
  alert(a);
</script>
<script>
    var a =1;
</script>

結果會報錯 代碼自上而下執行 沒有解析下面的var a=1;

<script>
   var a =1;
</script>
<script>
  alert(a);
</script>

結果是1; 會把a=1存起來 執行到下一個script 會在小倉庫裏找a

局部作用域

  1. 函數內部也是一個空間 函數構建的空間 可以被看作一個局部作用域
  2. 如果局部作用域的預解析的空間 沒有找到 那麼我的代碼執行 會從上一級作用域尋找 上一級作用域不能在下一級作用域尋找
  3. 預解析的空間 :AO ----活動對象
<script>
  var a =1;
  function fn1() {
      alert(a);
      var a =2;
  }
  fn1();
  alert(a);
</script>

第一個結果是 undefined 第二個結果是 1

  1. 預解析 AO分析
  • a:undefined fn1{}
  1. 代碼執行 a=1
  • fn1執行 :進入函數內部 1預解析 a:undefined 2 執行 alert(a) a=2
  • alert(a) 所以結果是先 undefined 後1
<script>
  var a =1;
  function fn1() {
      alert(a);
  }
  fn1();
  alert(a);
</script>

結果是1 1

  1. 預解析
  • a:undefined fn1{}
  1. 代碼執行 a=1
  • fn1執行 :進入函數內部 1預解析 預解析是空 2 執行 alert(a) 跳出函數在全局中尋找a a=1 所以結果是1
  • alert(a) 所以結果是先 1 後1

參數

  1. 形參 相當於隱式聲明 在AO上爲undefined
  2. 實參 會在AO分析時候 給形參一個初始值
<script>
  var a =1;
  function fn1(a) {
      alert(a);
      a =2;
  }
  fn1();
  alert(a);
</script>
  1. 預解析
  • a:undefined fn1{}
  1. 代碼執行 a=1
  • fn1執行 :進入函數內部 1預解析 形參相當於聲明變量a:undefined 2 執行 alert(a)所以結果是undefined 之後賦值a=2;
  • alert(a) 所以結果是先 undefined 後1
<script>
  var a =1;
  function fn1(a) {
      alert(a);
      a =2;
      alert(a);
  }
  fn1(a);
  alert(a);
</script>
  1. 預解析
  • a:undefined fn1{}
  1. 代碼執行 a=1
  • fn1執行 :進入函數內部 1預解析 實參傳值 a=1 2 執行 alert(a)所以結果是1 之後賦值a=2;
  • alert(a) 所以結果是先 1 後2 再 1
<script>
   var a =1;
   function f1() {
    alert(a);
    a=2;
   }
   f1();
   alert(a);
</script>

結果是 1 2

<script>
  var age =99;
  function t(age) {
      alert(age);
  }
  t(5);
  t();
</script>
  1. 預解析
  • age:undefined t:function{}
  1. 代碼執行 age=99
  • t(5)執行 :進入函數內部 1預解析 實參傳值 age=5 2 執行 alert(age)所以結果是5
  • t()執行 進入函數 1 預解析 形參相當於聲明變量a:undefined alert(age) 所以結果是先5 後undefined
<script>
  function t2(green) {
      alert(green);
      function green() {

      }
      green="hello";
      alert(green);
  }
  t2(null);
  1. 預解析
  • green:null 進入函數內部 有一個函數聲明 會覆蓋 green=function green() {}
  1. 代碼執行 alert(green) 結果是 function
  • green:hello
  • alert(green) 結果是hello 所以 第一個是函數體 第二個是hello
<script>
  function a(b) {
      alert(b);
      function b() {
          alert(b);
      }
      b();
  }
  a(1);
</script>
  1. 預解析
  • b=1 進入函數內部 有一個函數聲明 會覆蓋 b=function b(){}
  1. 代碼執行 alert(b) 結果是 function
  • b() 執行 進入b(){}內部 並沒有 var b 跳出當前函數 找到b爲function 所以alert(b) 是函數本身 結果兩個都是函數本身
<script>
  function a(b) {
      alert(b);
      b=function(){
          alert(b);
      }
      b();
  }
  a(1);
</script>
  1. 預解析
  • b=1 進入函數內部 沒有函數聲明 變量聲明
  • 代碼執行 alert(b) 結果是1
  • 賦值b=function(){}
  1. b()執行 進入函數體內部 沒有var b 跳出 b=function 結果是function 所以第一個是1 第二個是函數本身

作用域分析

  1. 先看看有沒有參數 實參會把形參初始化 如果只有形參 那麼形參爲undefined
  2. 再看看有沒有變量聲明 函數會把同名變量覆蓋 包括實參

jquery部分代碼

  1. 傳window是爲了性能
  2. 不穿undefined 是爲了函數內部不被污染
<script>
  (function (window,undefined) {
      function(){
          function(){
              function(){
                  window.document.getElementById()
              }
          }
      }
  })(window);
</script>

如果函數內部沒有 window 那麼document.getElementById()要執行 會跳出這個函數 當層數太多 性能就會很低 所以會實參會傳一個window到函數內部 形參undefined 初始值就是undefined 不用實參傳 再低版本的ie中 undefined可以被賦值 如果在函數外部 定義undefined=1 實參傳undefined 那麼函數內部undefined 就會被污染爲1 如果函數內部做判斷 if(a==undefined)就不可以

作用域鏈

內層作用域在尋找變量時候未找到 會沿着作用域上的AO 向上尋找 直到全局

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章