javascript--13---閉包

獲取局部變量

<script>
  function fn1() {
      var a ="月薪10w";
  }
  alert(a);
</script>

如何獲取內部變量

  1. 作爲函數返回值
<script>
  function fn1() {
      var a ="月薪10w";
      return a;
  }
  alert(fn1());
</script>
  1. 通過變量向外傳遞
<script>
var b="";
  function fn1() {
      var a ="月薪10w";
     b=a;
  }
  fn1();
  alert(b);
</script>
  1. 通過函數傳參
<script>
  function fn1() {
      var a ="月薪10w";
    fn2(a);
  }
  function fn2(str){
      alert(str);
  }
  fn1();
</script>

條件和循環體

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

會有結果1

<script>
 alert(a);
  if (false){
      var a =10;
  } 
</script>

結果是undefined

<script>
  if (1){
      function fn1() {
          
      }
  }
  alert(fn1);

結果是函數體

  1. {}不代表作用域 但是有例外
<script>
 alert(fn1);
  if (1){
      function fn1() {
          
      }
  }

結果是 undefined 這是es6的規範 在es6中 花括號{}會被看作是代碼塊 在{}當中聲明一個函數 相當於 var 聲明 所以結果是undefined

<script>
 alert(fn1);
      function fn1() {
          
      }

結果是函數體

  1. 儘量不要在代碼塊中聲明函數 否則 調用會出問題
<script>
fn1();
  if (1){
      function fn1() {
            alert(1);
      }
  }
</script>

會報錯 因爲此時看作是代碼塊 相當於var 聲明var a=fn1(){}這時候fn1();是不會執行的 會報錯

<script>
    alert(fn1);
  if (1){
      function fn1() {
            alert(1);
      }
  }
</script>

結果是個undefined

閉包

<script>
   function t1() {
       var age =20;
       function t2() {
           alert(age);
       }
       return t2;
   }
   var tmp =t1();
   var age =1000;
   tmp();

</script>

結果是 20 AO分析

  • 第1步 AO{t1:function,tmp:un,age:un}
  • 第2步 tmp=t1(); t1執行
    進入函數體 AO{age:un,t2:fun} 執行AO{age:20,t2:fn} 遇到return t2 跳出函數 t2 =function t2(){} 所以 AO{ tmp=t2, age:1000}
  • tmp執行 進入函數t2 AO 沒發現變量聲明 從上級尋找 age爲20
  1. 我們在返回函數的時候 並不是單純的返回了一個函數 而是把作用域鏈返回了 如果沒有變量聲明會沿着作用域鏈往上找
  2. 函數的作用域 取決於聲明時 而不取決於調用時

閉包是什麼

  1. 有函數套嵌
  2. 內部函數使用了外部函數的變量
  3. 內部函數的使用外部函數的那些變量和參數會永久保存
  4. 垃圾回收機制:當環境都不存在有某個對象/數據的引用時,這個數據會自動被回收 但是全局變量不會被回收
  5. 返回函數時 並非孤立的函數 而是連同周圍的環境 AO 打了一個包 成了一個封閉的環境包 共同返回出來----閉包
<script>
    var age = 10;
   function t1() {
       var age =20;
       return function t2() {
           alert(++age);
       }
   }
   var t3=t1();
   t3();
   t3();
   t3();
   alert(age);

結果 21 22 23 10

console.log(function () {} === function(){});
 console.log([]===[]);
 console.log({}==={});

這些都不一樣 不等於

var a =function(){};
    var b =a;
    console.log(a==b);

這是相等的 變量存儲 function {} []存儲的是個地址

<script>
    var age = 10;
   function t1() {
       var age =20;
       return function t2() {
           alert(++age);
       }
   }
   var t3=t1();
    var t4=t1();
    t3();
    t4();
</script>

結果是 21 21 因爲t3 t4 表示的不是一個函數 雖然都是t2

<script>
   function foo() {
       var a=2;
       function baz() {
           console.log(a);
       }
       bar(baz);
   }
    function bar(fn) {
        var a=3;
        fn();
    }
    foo();
</script>

結果是2 函數的作用域取決於聲明時 不是調用時

計數器

<script>
  window.cnt=0
    function inc() {
        cnt++;
    }
    inc();
  inc();
  console.log(cnt);
</script>
<script>
    var cnt=100;
    inc();
    console.log(cnt);
</script>

結果是 2 101 會污染變量

<script>
    function counter(){
        var cnt=0;
        var cont =function(){
            return ++cnt;
        }
        return cont;
    }
    var inc =counter();
  console.log(inc());
</script>
<script>
    var cnt=100;
    inc();
    console.log(inc())
</script>

結果是1 3 沒有污染變量

<script>
    function counter(){
        var cnt=0;
        return function(){
            return ++cnt;
        }
    }
    var inc =counter();
  console.log(inc());
</script>
<script>
    var cnt=100;
    inc();
    console.log(inc())
</script>

簡化版本

<script>
   var inc = (function (){
        var cnt=0;
        return function(){
            return ++cnt;
        }
    })();
    var inc =counter();
  console.log(inc());
</script>
<script>
    var cnt=100;//如果繼續var inc =100;又會污染變量
    inc();
    console.log(inc())
</script>

解決變量污染

<script>
    var juce ={};
    juce.inc = (function (){
        var cnt=0;
        return function(){
            return ++cnt;
        }
    })();
  console.log(juce.inc());
</script>
<script>
    var cnt=100;
    inc();
    console.log(inc())
</script>

js的命名空間 別人不能用裏面的函數

for循環中的閉包

方法一:通過自定義屬性

<script>
   var inp= document.getElementsByTagName("input");
   for (var i=0;i<inp.length;i++){
       inp[i].i=i;
       inp[i].onclick = function () {
           inp[this.i].style.backgroundColor = "red";
       }
   }
   console.log(i);
</script>

方法二:使用let

<script>
   var inp= document.getElementsByTagName("input");
   for (let i=0;i<inp.length;i++){
       inp[i].onclick = function () {
           inp[i].style.backgroundColor = "red";
       }
   }
   console.log(i);
</script>

第三種:使用this 第四種:for循環每執行一次 都會立即執行一個匿名函數 並且匿名函數的作用域中 傳入了當時的i

for (var i=0;i<inp.length;i++){
       (function(i){
           inp[i].onclick = function () {
               inp[i].style.backgroundColor = "red";
           }})(i);
   }

第五種:將變量傳進作用域

for (var i=0;i<inp.length;i++){
       (function(){
           var arg = i;
           inp[arg].onclick = function () {
               inp[arg].style.backgroundColor = "red";
           }})();
   }

第六種:循環時候立即執行函數 將變量傳進作用域

for (var i=0;i<inp.length;i++){
           inp[i].onclick = function (i) {
               return function() {
                   inp[i].style.backgroundColor = "red";
               }
           }(i);
   }

方法七:基本包裝類型 通過 new 使用 Function 的構造函數 創建 Function 實例實現,由於傳入的函數體的內容是字符串,故 Function 得到的是一個字符串拷貝,而沒有得到 i 的引用(這裏是先獲取 i.toString()然後與前後字符串拼接成一個新的字符串,Function 對其進行反向解析成 JS 代碼)

for(var i=0;i<inp.length;i++){
    inp[i].onclick = new Function(`inp[${i}].style.backgroundColor = "red";`);
}

方法九:

function fn(a) {
     alert(1);
 }
 console.log(fn.length);

結果是1,length是形參個數

for (var i=0;i<inp.length;i++){
       (inp[i].onclick = function () {
                   inp[arguments.callee.i].style.backgroundColor = "red";
           }).i=i;//arguments 參數對象  arguments.callee 參數對象所屬函數
   }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章