成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

理解 JavaScript 閉包

寵來也 / 734人閱讀

摘要:如何在初學(xué)就理解閉包你需要接著讀下去。這樣定義閉包是函數(shù)和聲明該函數(shù)的詞法環(huán)境的組合。小結(jié)閉包在中隨處可見。閉包是中的精華部分,理解它需要具備一定的作用域執(zhí)行棧的知識。

這是本系列的第 4 篇文章。

作為 JS 初學(xué)者,第一次接觸閉包的概念是因?yàn)閷懗隽祟愃葡旅娴拇a:

for (var i = 0; i < helpText.length; i++) {
  var item = helpText[i];
  document.getElementById(item.id).click = function() {
    showHelp(item.help);
  }
}

給列表項(xiàng)循環(huán)添加事件處理程序。當(dāng)你點(diǎn)擊列表項(xiàng)時(shí)不會(huì)有任何反應(yīng)。如何在初學(xué)就理解閉包?你需要接著讀下去。

§ 什么是閉包

說閉包前,你還記得詞法作用域嗎?

var num = 0;
function foo() {
  var num = 1;
  function bar() {
    console.log(num);
  }
  bar();
}
foo(); // 1

執(zhí)行上面的代碼打印出 1。

bar 函數(shù)是 foo 函數(shù)的內(nèi)部函數(shù),JS 的詞法作用域允許內(nèi)部函數(shù)訪問外部函數(shù)的變量。那我們可不可以在外部訪問內(nèi)部函數(shù)的變量呢?理論上不允許。

但是我們可以通過某種方式實(shí)現(xiàn),即將內(nèi)部函數(shù)返回。

function increase() {
  let count = 0;
  function add () {
    count += 1;
    return count;
  }
  return add;
}

const addOne = increase();

addOne(); // 1
addOne(); // 2
addOne(); // 3

內(nèi)部函數(shù)允許訪問其父函數(shù)的內(nèi)部變量,那么將內(nèi)部函數(shù)返回到出來,它依舊引用著其父函數(shù)的內(nèi)部變量。

這里就產(chǎn)生了閉包。

簡單來說,可以把閉包理解為函數(shù)返回函數(shù)。

上面的代碼中,當(dāng) increase 函數(shù)執(zhí)行,壓入執(zhí)行棧,執(zhí)行完畢返回一個(gè) add 函數(shù)的引用,所以 increase 函數(shù)內(nèi)部的變量對象依舊保存在內(nèi)存中,不會(huì)被銷毀。

調(diào)用 addOne 函數(shù),相當(dāng)于執(zhí)行內(nèi)部函數(shù) add,它可以訪問其父函數(shù)的內(nèi)部變量,從而修改變量 count。而調(diào)用 addOne 函數(shù)所在的環(huán)境為全局作用域,不是定義 add 函數(shù)時(shí)的函數(shù)作用域。

所以,我理解的閉包是一個(gè)函數(shù),它在執(zhí)行時(shí)與其定義時(shí)所處的詞法作用域不一致,并且具有能夠訪問定義時(shí)詞法作用域的能力。MDN 這樣定義:閉包是函數(shù)和聲明該函數(shù)的詞法環(huán)境的組合

§ 閉包的利與弊 ◆ 利

第一,閉包可以在函數(shù)外部讀取函數(shù)內(nèi)部的變量。

var Counter = (function() {
  var privateCounter = 0;
  function changeBy(val) {
    privateCounter += val;
  }
  return {
    increment: function() {
      changeBy(1);
    },
    decrement: function() {
      changeBy(-1);
    },
    value: function() {
      return privateCounter;
    }
  }
})();

Counter.value(); // 0
Counter.increment();
Counter.increment();
Counter.value(); // 2
Counter.decrement();
Counter.value(); / 1

上面這種模式稱為模塊模式。我們使用立即執(zhí)行函數(shù) IIFE 將代碼私有化但是提供了可訪問的接口,通過公共接口來訪問函數(shù)私有的函數(shù)和變量。

第二,閉包將內(nèi)部變量始終保存在內(nèi)存中。

function type(tag) {
  return function (data) {
    return Object.prototype.toString.call(data).toLowerCase() === "[object " + tag + "]";
  }
}

var isNum = type("number");
var isString = type("string");

isNum(1); // true
isString("abc"); // true

利用閉包將內(nèi)部變量(參數(shù))tag 保存在內(nèi)存中,來封裝自己的類型判斷函數(shù)。

◆ 弊

第一,既然閉包會(huì)將內(nèi)部變量一直保存在內(nèi)存中,如果在程序中大量使用閉包,勢必造成內(nèi)存的泄漏。

$(document).ready(function() {
  var button = document.getElementById("button-1");
  button.onclick = function() {
    console.log("hello");
    return false;
  };
});

在這個(gè)例子中,click 事件處理程序就是一個(gè)閉包(在這里是個(gè)匿名函數(shù)),它將引用著 button 變量;而 button 在這里本身依舊引用著這個(gè)匿名函數(shù)。從而產(chǎn)生循環(huán)引用,造成網(wǎng)頁的性能問題,在 IE 中可能會(huì)內(nèi)存泄漏。

解決辦法就是手動(dòng)解除引用。

$(document).ready(function() {
  var button = document.getElementById("button-1");
  button.onclick = function() {
    console.log("hello");
    return false;
  };
  button = null; // 添加這一行代碼來手動(dòng)解除引用
});

第二,如果你將函數(shù)作為對象使用,將閉包作為它的方法,應(yīng)該特別注意不要隨意改動(dòng)函數(shù)的私有屬性。

§ 閉包的經(jīng)典問題 ◆ 循環(huán)

現(xiàn)在我們來解決一下文章開頭出現(xiàn)的問題。

function makeHelpCallback(help) {
  return function() {
    showHelp(help);
  };
}

for (var i = 0; i < helpText.length; i++) {
  var item = helpText[i];
  document.getElementById(item.id).click = makeHelpCallback(item.help);
}

額外聲明一個(gè) makeHelpCallBack 的函數(shù),將循環(huán)每次的上下文環(huán)境通過閉包保存起來。

◆ setTimeout
for (var i = 0; i < 5; i++) {
  setTimeout(function() {
    console.log(i);
  }, 1000);
};

結(jié)果為 1 秒后,打印 5 個(gè) 5。

我們可以利用閉包保留詞法作用域的特點(diǎn),來修改代碼達(dá)到目的。

for (var i = 0; i < 5; i++) {
  setTimeout((function(i) {
    return function () {
      console.log(i);
    }
  }(i)), 1000);
};

結(jié)果為 1 秒后,依次打印 0 1 2 3 4。

§ 小結(jié)

閉包在 JS 中隨處可見。

閉包是 JS 中的精華部分,理解它需要具備一定的作用域、執(zhí)行棧的知識。理解它你將收獲巨大,你會(huì)在 JS 學(xué)習(xí)的道路上走得更遠(yuǎn),比如會(huì)在后面的文章來討論高階函數(shù)和柯里化的問題。

◆ 文章參考

閉包 | MDN

學(xué)習(xí) JavaScript 閉包 | 阮一峰

Understanding JavaScript Closures: A practical Approach | Paul Upendo

閉包造成問題泄漏的解決辦法 | CSDN

§ JavaScript 系列文章

理解 JavaScript 執(zhí)行棧

理解 JavaScript 作用域

理解 JavaScript 數(shù)據(jù)類型與變量

歡迎關(guān)注我的公眾號 cameraee

前端技術(shù) | 個(gè)人成長

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/100131.html

相關(guān)文章

  • 理解Javascript閉包

    摘要:但是閉包也不是什么復(fù)雜到不可理解的東西,簡而言之,閉包就是閉包就是函數(shù)的局部變量集合,只是這些局部變量在函數(shù)返回后會(huì)繼續(xù)存在??上У氖?,并沒有提供相關(guān)的成員和方法來訪問閉包中的局部變量。 (收藏自 技術(shù)狂) 前言:還是一篇入門文章。Javascript中有幾個(gè)非常重要的語言特性——對象、原型繼承、閉包。其中閉包 對于那些使用傳統(tǒng)靜態(tài)語言C/C++的程序員來說是一個(gè)新的語言特性。本文將...

    dayday_up 評論0 收藏0
  • Javascript閉包入門(譯文)

    摘要:也許最好的理解是閉包總是在進(jìn)入某個(gè)函數(shù)的時(shí)候被創(chuàng)建,而局部變量是被加入到這個(gè)閉包中。在函數(shù)內(nèi)部的函數(shù)的內(nèi)部聲明函數(shù)是可以的可以獲得不止一個(gè)層級的閉包。 前言 總括 :這篇文章使用有效的javascript代碼向程序員們解釋了閉包,大牛和功能型程序員請自行忽略。 譯者 :文章寫在2006年,可直到翻譯的21小時(shí)之前作者還在完善這篇文章,在Stackoverflow的How do Java...

    Fourierr 評論0 收藏0
  • 【譯】理解JavaScript閉包

    摘要:當(dāng)面試中讓我解釋一下閉包時(shí)我懵逼了。這個(gè)解釋開始可能有點(diǎn)晦澀,讓我們抽絲剝繭摘下閉包的真面目。此文不詳述作用域有專門的主題闡述,不過作用域是理解閉包原理的基礎(chǔ)。這才是閉包的真正便利之處。閉包使用不當(dāng)就會(huì)很坑。 原文鏈接 為什么深度學(xué)習(xí)JavaScript? JavaScript如今是最流行的編程語言之一。它運(yùn)行在瀏覽器、服務(wù)器、移動(dòng)設(shè)備、桌面應(yīng)用,也可能包括冰箱。無需我舉其他再多不相干...

    岳光 評論0 收藏0
  • 通過示例學(xué)習(xí)JavaScript閉包

    摘要:譯者按在上一篇博客,我們通過實(shí)現(xiàn)一個(gè)計(jì)數(shù)器,了解了如何使用閉包,這篇博客將提供一些代碼示例,幫助大家理解閉包。然而,如果通過代碼示例去理解閉包,則簡單很多。不過,將閉包簡單地看做局部變量,理解起來會(huì)更加簡單。 - 譯者按: 在上一篇博客,我們通過實(shí)現(xiàn)一個(gè)計(jì)數(shù)器,了解了如何使用閉包(Closure),這篇博客將提供一些代碼示例,幫助大家理解閉包。 原文: JavaScript Clos...

    xingpingz 評論0 收藏0
  • JavaScript中的閉包

    摘要:閉包引起的內(nèi)存泄漏總結(jié)從理論的角度將由于作用域鏈的特性中所有函數(shù)都是閉包但是從應(yīng)用的角度來說只有當(dāng)函數(shù)以返回值返回或者當(dāng)函數(shù)以參數(shù)形式使用或者當(dāng)函數(shù)中自由變量在函數(shù)外被引用時(shí)才能成為明確意義上的閉包。 文章同步到github js的閉包概念幾乎是任何面試官都會(huì)問的問題,最近把閉包這塊的概念梳理了一下,記錄成以下文章。 什么是閉包 我先列出一些官方及經(jīng)典書籍等書中給出的概念,這些概念雖然...

    HmyBmny 評論0 收藏0

發(fā)表評論

0條評論

最新活動(dòng)
閱讀需要支付1元查看
<