最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

JavaScript 閉包:函數(shù)背后的“背包”(一文詳解)

 更新時間:2026年05月25日 09:17:58   作者:yqcoder  
文章詳細(xì)解釋了JavaScript閉包的概念及其作用,包括數(shù)據(jù)封裝、函數(shù)柯里化和異步回調(diào)中的的狀態(tài)保持,并通過實(shí)例展示了閉閉如何工作以及如何避免潛在的內(nèi)存泄漏問題,感興趣的朋友一起看看吧

?? 什么是閉包?

官方定義
閉包是指有權(quán)訪問另一個函數(shù)作用域中變量的函數(shù)。

通俗解釋
想象一個函數(shù)是一個,他出生時背了一個背包(Scope/作用域)。
這個背包里裝著他出生時周圍環(huán)境中的所有變量。
即使這個人走到了世界的盡頭(全局環(huán)境),或者他的父母(外部函數(shù))已經(jīng)去世(執(zhí)行完畢),他依然背著那個背包,可以隨時拿出里面的東西使用。

一句話總結(jié)
閉包 = 函數(shù) + 函數(shù)能訪問到的自由變量(背包里的東西)。

1. ?? 核心原理:為什么會有閉包?

要理解閉包,首先要理解 JS 的詞法作用域(Lexical Scoping)垃圾回收機(jī)制。

正常情況:函數(shù)執(zhí)行完,變量銷毀

function outer() {
  let a = 10;
  console.log(a);
}
outer(); // 10
// 函數(shù)執(zhí)行完畢,a 被垃圾回收器回收,內(nèi)存釋放。

特殊情況:內(nèi)部函數(shù)引用了外部變量

function outer() {
  let a = 10;
  function inner() {
    console.log(a); // inner 引用了 outer 的變量 a
  }
  return inner; // 將 inner 返回出去
}
const myFunc = outer();
myFunc(); // 10

發(fā)生了什么?

  1. outer 執(zhí)行完畢,按理說 a 應(yīng)該被銷毀。
  2. 但是,inner 函數(shù)被返回并賦值給了 myFunc
  3. inner 的定義中包含了對 a 的引用。
  4. JS 引擎發(fā)現(xiàn):“嘿,inner 還在外面被人拿著呢,它還要用 a,所以我不能銷毀 a!”
  5. 于是,a 所在的內(nèi)存空間被保留下來,形成了閉包

2. ??? 閉包的三大核心作用

閉包不僅僅是理論,它在實(shí)際開發(fā)中有三個非常強(qiáng)大的用途:

? 作用一:數(shù)據(jù)封裝與私有變量(模擬私有屬性)

在 ES6 Class 出現(xiàn)之前,JS 沒有真正的“私有變量”。閉包是實(shí)現(xiàn)模塊化和數(shù)據(jù)隱藏的核心手段。

場景:創(chuàng)建一個計數(shù)器,外部只能調(diào)用 increment,無法直接修改 count。

function createCounter() {
  let count = 0; // 私有變量,外部無法直接訪問
  return {
    increment: function () {
      count++;
      return count;
    },
    decrement: function () {
      count--;
      return count;
    },
    getCount: function () {
      return count;
    },
  };
}
const counter = createCounter();
console.log(counter.increment()); // 1
console.log(counter.increment()); // 2
console.log(counter.count); // undefined ? 無法直接訪問

價值:保護(hù)數(shù)據(jù)不被意外篡改,提供清晰的 API 接口。

? 作用二:函數(shù)柯里化與參數(shù)復(fù)用

閉包可以“記住”之前傳入的參數(shù),從而實(shí)現(xiàn)函數(shù)的部分應(yīng)用(Partial Application)。

場景:固定稅率計算。

function makeTaxCalculator(taxRate) {
  // taxRate 被閉包“記住”了
  return function (price) {
    return price * taxRate;
  };
}
const calcVAT = makeTaxCalculator(0.13); // 增值稅率 13%
const calcIncomeTax = makeTaxCalculator(0.2); // 所得稅率 20%
console.log(calcVAT(100)); // 13
console.log(calcIncomeTax(100)); // 20

價值:減少重復(fù)傳參,提高代碼復(fù)用性。

? 作用三:異步回調(diào)中的狀態(tài)保持

在異步編程(如定時器、AJAX、事件監(jiān)聽)中,閉包確?;卣{(diào)函數(shù)執(zhí)行時,依然能訪問到定義時的上下文變量。

場景:延遲打印日志。

function logAfterDelay(msg, delay) {
  setTimeout(function () {
    // 這里的 msg 和 delay 即使在 setTimeout 觸發(fā)時(幾秒后)依然可用
    console.log(`${msg} after ${delay}ms`);
  }, delay);
}
logAfterDelay("Hello", 1000);

3. ?? 代碼實(shí)戰(zhàn):經(jīng)典面試題解析

? 經(jīng)典陷阱:循環(huán)中的閉包

這是面試中最常考的閉包問題。

for (var i = 1; i <= 5; i++) {
  setTimeout(function timer() {
    console.log(i);
  }, i * 1000);
}

預(yù)期輸出:1, 2, 3, 4, 5
實(shí)際輸出:6, 6, 6, 6, 6 ??

原因

  • var 沒有塊級作用域,所有定時器共享同一個全局變量 i。
  • 當(dāng)定時器執(zhí)行時,循環(huán)已經(jīng)結(jié)束,i變成了 6。

? 解決方案 1:使用 IIFE(立即執(zhí)行函數(shù))創(chuàng)建閉包

for (var i = 1; i <= 5; i++) {
  (function (j) {
    setTimeout(function timer() {
      console.log(j); // j 是每次循環(huán)獨(dú)立的副本
    }, j * 1000);
  })(i);
}

原理:IIFE 為每次循環(huán)創(chuàng)建了一個新的作用域,將當(dāng)前的 i 值作為參數(shù) j 傳入并保存。

? 解決方案 2:使用let(推薦)

for (let i = 1; i <= 5; i++) {
  setTimeout(function timer() {
    console.log(i);
  }, i * 1000);
}

原理let 具有塊級作用域,JS 引擎會為每次循環(huán)迭代創(chuàng)建一個新的綁定。

4. ?? 雙刃劍:內(nèi)存泄漏與性能

閉包雖然強(qiáng)大,但濫用會導(dǎo)致內(nèi)存泄漏。

?? 為什么會導(dǎo)致內(nèi)存泄漏?

正常情況下,函數(shù)執(zhí)行完后,局部變量會被回收。
但如果形成了閉包,且外部一直持有對該閉包函數(shù)的引用,那么閉包所引用的所有外部變量都不會被回收。

危險示例

function hugeDataHandler() {
  const hugeArray = new Array(1000000).fill("data"); // 占用大量內(nèi)存
  return function () {
    console.log(hugeArray.length); // 只要這個函數(shù)存在,hugeArray 就不會被回收
  };
}
const handler = hugeDataHandler();
// 如果你不再需要 handler,必須手動解除引用
handler = null; // ? 允許 GC 回收 hugeArray

??? 最佳實(shí)踐

  1. 及時解除引用:如果不再需要閉包函數(shù),將其賦值為 null。
  2. 避免在閉包中引用巨大的無用對象。
  3. 謹(jǐn)慎使用全局閉包:盡量縮小閉包的作用范圍。

?? 總結(jié)

特性說明
本質(zhì)函數(shù) + 引用的自由變量
核心能力延長變量生命周期,實(shí)現(xiàn)數(shù)據(jù)私有化
主要用途1. 封裝私有變量
2. 柯里化/參數(shù)復(fù)用
3. 異步回調(diào)狀態(tài)保持
副作用可能導(dǎo)致內(nèi)存泄漏,增加內(nèi)存占用
解決循環(huán)陷阱使用 let 或 IIFE

到此這篇關(guān)于JavaScript 閉包:函數(shù)背后的“背包”的文章就介紹到這了,更多相關(guān)js閉包內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評論

齐河县| 长宁区| 来宾市| 翁牛特旗| 平塘县| 清镇市| 进贤县| 金湖县| 周至县| 八宿县| 太和县| 德清县| 孟村| 云安县| 南宫市| 汤阴县| 临西县| 农安县| 莒南县| 隆昌县| 旅游| 大足县| 科尔| 桃园市| 安义县| 霍林郭勒市| 蒙自县| 合山市| 余姚市| 阜宁县| 兴隆县| 萍乡市| 秭归县| 汶川县| 鸡东县| 庐江县| 白玉县| 亳州市| 台南市| 锦屏县| 平阳县|