首頁 >web前端 >js教程 >JavaScript閉包的輕鬆理解

JavaScript閉包的輕鬆理解

黄舟
黄舟原創
2017-03-20 14:48:572126瀏覽

閉包機制是JavaScript的重點與困難點,本文希望能幫助大家輕鬆的學習閉包。以下跟著小編一起來看吧

摘要

閉包機制是Javascript的重點與困難點,本文希望能幫助大家輕鬆的學習閉包

一、什麼是閉包?

閉包就是可以存取另一個函數作用域中變數的函數。

下面列舉常見的閉包實作方式,以例子講解閉包概念

function f1(){
    var n=999;
    nAdd=function(){n+=1}
    function f2(){
      alert(n);
    }
    return f2;
  }
  var result=f1();
  result(); // 999
  nAdd();
  result(); // 1000

f1是f2的父函數,而f2被賦給了一個全域變數(return的值) ,這導致f2始終在記憶體中,而f2的存在依賴f1,因此f1也始終在記憶體中,不會在呼叫結束後,被垃圾回收機制(garbage collection)回收,這便形成了閉包。

因此,可以這麼理解。 閉包機制就是,如果A函數引用了另一個函數B的變量,但B返回後A仍沒有返回,仍存在,因為A的引用,所以B的所有局部變數並不會隨B退出而註銷,會一直存在,直到A註銷。此時A就是閉包。

二、閉包的this指標

#閉包通常在全域環境呼叫的,所以this通常指向window,具體情況還是需要視執行環境而言,總之this指向執行環境。

若需要閉包的this指向閉包的包含物件,則需要將包含物件的this當作變數傳進閉包。

三、使用閉包的注意點

  1. #由於閉包會使得函數中的變數都保存在記憶體中,記憶體消耗很大,所以不能濫用閉包,否則會造成網頁的效能問題,在IE中可能導致記憶體外洩。解決方法是,在退出函數之前,將不使用的局部變數全部刪除

  2. 閉包會在父函數外部,改變父函數內部變數的值。所以,如果你把父函數當作物件(object)使用,把閉包當作它的公用方法(Public Method),把內部變數當作它的私有屬性 (private value),這時一定要小心,不要隨便改變父函數內部變數的值。

四、解決一道閉包常見面試題

問題:

#
function onMyLoad(){
  /*
  抛出问题:
  此题的目的是想每次点击对应目标时弹出对应的数字下标 0~4,但实际是无论点击哪个目标都会弹出数字5
  问题所在:
  arr 中的每一项的 onclick 均为一个函数实例(Function 对象),这个函数实例也产生了一个闭包域,
  这个闭包域引用了外部闭包域的变量,其 function scope 的 closure 对象有个名为 i 的引用,
  外部闭包域的私有变量内容发生变化,内部闭包域得到的值自然会发生改变
  */
  var arr = document.getElementsByTagName("p");
  for(var i = 0; i < arr.length;i++){
  arr[i].onclick = function(){
   alert(i);
  }
  }
 }

解決方法

1、在外面再加一層函數,將i當作函數參數傳進來,這樣每次保存的是函數內部的變量,與外部i不是同一個記憶體空間,而每次呼叫函數都會產生一個局部變量,所以可以保證每次保存的值互不影響。

for(var i = 0; i<arr.length;i++){
 arr[i].onclick = (function(arg){
  return function () {
   alert(arg);
  }
 })(i);
}

2、用ES6新特let,將for循環的var i改成let i,這樣當前的i只在本輪循環有效,所以每一次循環的i其實都是一個新的變數。你可能會問,如果每一輪循環的變數i都是重新聲明的,那它怎麼知道上一輪循環的值,從而計算出本輪循環的值?這是因為 Javascript 引擎內部會記住上一輪循環的值,初始化本輪的變數i時,就在上一輪循環的基礎上進行計算。

以上是JavaScript閉包的輕鬆理解的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn