JS閉包、及閉包的應用場景


閉包:如大家所知,通俗講,可以訪問其他函數內部變量的函數

// 創建閉包最常見的方式函數作為返回值
function fn() {
  let name = "小帆";
  return function() {
    console.log(name);
  };
}
let log = fn();
log(); //打印“小帆”    --外部函數訪問內部變量

下面來實現一個簡單的demo:計數器

var number = 0;
function creat() {
  number = number + 1;
  console.log(number );
}
creat(); //確實實現了需求

//但是如果需要第二個計數器呢? //確定要像下面這樣寫嗎? var num = 0; function creat_1() { num = num + 1; console.log(num ); } creat_1();

如果我們需要的更多計數器,上面的寫法就感覺代碼很冗余了,這個時候可以考慮一下閉包:

function createNum() {
  var number = 0;
  return function() {
    number = number + 1;
    console.log(number );
  };
}

var fun1 = createNum();
fun1(); //1
fun1(); //2
var fun2 = createNum();
fun2(); //1
fun2(); //2

有一種經典題目:for循環里的定時器引發的思考

下面這道題的結果是多少?

for (var i = 0; i < 4; i++) {
  setTimeout(function() {
    console.log(i);
  }, 300);
}

依次打印0,1,2,3  ???,然而打印的全都是4

原因:JS 執行的時候首先會先執行主線程,異步相關的會存到異步隊列里,當主線程執行完畢開始執行異步隊列, 主線程執行完畢后,此時 i 的值為 4,說以在執行異步隊列的時候,打印出來的都是 4(這里需要大家對 event loop 有所了解(js 的事件循環機制))

要使其依次打印0,1,2,3,則可以考慮閉包:

//方法一:
//這個是通過自執行函數返回一個函數,然后在調用返回的函數去獲取自執行函數內部的變量,此為閉包
for (var i = 0; i < 4; i++) {
  setTimeout(
    (function(i) {
      return function() {
        console.log(i);
      };
    })(i),
    300
  );
}

//方法二:
// 大部分都認為方法一和方法二都是閉包,我認為方法一是閉包,而方法二是通過創建一個自執行函數,使變量存在這個自執行函數的作用域里
for (var i = 0; i < 4; i++) {
  (function(i) {
    setTimeout(function() {
      console.log(i);
    }, 300);
  })(i);
}

再舉一個例子:獲取多個元素並添加點擊事件

var op = document.querySelectorAll("p");
for (var j = 0; j < op.length; j++) {
  op[j].onclick = function() {
    console.log(j);
  };
}
//log出來的值是一樣的

// 解決辦法一:
for (var j = 0; j < op.length; j++) {
  (function(j) {
    op[j].onclick = function() {
      alert(j);
    };
  })(j);
}

// 解決辦法二:
for (var j = 0; j < op.length; j++) {
  op[j].onclick = (function(j) {
    return function() {
      alert(j);
    };
  })(j);
}

既然這樣,那每次遇到這種問題的時候我是不是可以都這樣使用閉包?

最后說一下,閉包有它的好處,也有它的壞處

閉包的缺點:閉包會導致內存占用過高,因為變量都沒有釋放內存,從而垃圾回收機制不會銷毀該變量。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM