偷偷摘套内射激情视频,久久精品99国产国产精,中文字幕无线乱码人妻,中文在线中文a,性爽19p

我以為自己懂閉包,直到遇見了它的真面目

開發(fā) 前端
簡(jiǎn)單來說,閉包是函數(shù)與其聲明時(shí)所處的詞法環(huán)境(也就是外部作用域變量的引用)的結(jié)合體。換句話說,閉包讓函數(shù)可以訪問其外層作用域中的變量,即使外層作用域已經(jīng)執(zhí)行結(jié)束。

每個(gè) JavaScript 開發(fā)者都認(rèn)為自己理解閉包,直到他們發(fā)現(xiàn)其實(shí)并非如此。

閉包是個(gè)看似簡(jiǎn)單,但一不小心就會(huì)出現(xiàn)意外行為的概念。

我自認(rèn)為已經(jīng)掌握閉包,結(jié)果碰到了意想不到的問題。

接下來,我們一起好好剖析一下閉包。

閉包到底是什么?

簡(jiǎn)單來說,閉包是函數(shù)與其聲明時(shí)所處的詞法環(huán)境(也就是外部作用域變量的引用)的結(jié)合體。

換句話說,閉包讓函數(shù)可以訪問其外層作用域中的變量,即使外層作用域已經(jīng)執(zhí)行結(jié)束。

閉包 = 函數(shù) + 它所“保留”的詞法作用域。

聽起來很直觀吧?

來看個(gè)經(jīng)典例子:

function outerFunction() {
  let count = 0;
  function innerFunction() {
    console.log(count);
  }
  return innerFunction;
}

const fn = outerFunction();
fn(); // 0

盡管 outerFunction() 已經(jīng)執(zhí)行完畢并返回,innerFunction() 仍能訪問 count。這就是閉包的魔力。

復(fù)雜部分:循環(huán)里的閉包陷阱

如果閉包這么簡(jiǎn)單,大家不會(huì)頭疼。

問題出在循環(huán)里。

假設(shè)你想在循環(huán)中創(chuàng)建函數(shù)數(shù)組,每個(gè)函數(shù)打印它在循環(huán)中的索引。

你猜會(huì)輸出什么?

const funcs = [];
for (var i = 0; i < 3; i++) {
  funcs.push(() => console.log(i));
}
funcs[0](); // ?
funcs[1](); // ?
funcs[2](); // ?

如果你猜是 0 1 2,恭喜你,錯(cuò)了。

實(shí)際輸出是:

3
3
3

這是什么情況?

原因和解決方案

問題在于:

var i 是函數(shù)作用域,不是塊級(jí)作用域。當(dāng)函數(shù)執(zhí)行時(shí),循環(huán)已經(jīng)結(jié)束,i 的值變成了3。

解決方案一:用 let 替代 var

let 是塊級(jí)作用域,每次循環(huán)都會(huì)捕獲一個(gè)新的 i。

const funcs = [];
for (let i = 0; i < 3; i++) {
  funcs.push(() => console.log(i));
}
funcs[0](); // 0 ?
funcs[1](); // 1 ?
funcs[2](); // 2 ?

這樣問題迎刃而解。

解決方案二:使用立即執(zhí)行函數(shù)表達(dá)式(IIFE)

如果只能用 var,用 IIFE 創(chuàng)建單獨(dú)作用域:

const funcs = [];

for (var i = 0; i < 3; i++) {
  (function(index) {
    funcs.push(() => console.log(index));
  })(i);
}

funcs[0](); // 0 ?
funcs[1](); // 1 ?
funcs[2](); // 2 ?

每個(gè) IIFE 都“凍結(jié)”了當(dāng)時(shí)的 i 值,保證正確輸出。

閉包在實(shí)際開發(fā)中的用武之地

閉包不僅是理論,更是日常開發(fā)中不可或缺的工具。

1. 數(shù)據(jù)隱私(封裝)

想要?jiǎng)?chuàng)建私有變量?閉包幫你實(shí)現(xiàn)。

function createCounter() {
  let count = 0;
  return {
    increment: () => count++,
    getCount: () => count
  };
}

const counter = createCounter();
counter.increment();
console.log(counter.getCount()); // 1 ?

count 不可被外部直接訪問,實(shí)現(xiàn)了私有狀態(tài)。

2. 記憶狀態(tài)的事件監(jiān)聽器

事件監(jiān)聽器需要記住狀態(tài)時(shí),閉包非常實(shí)用。

function attachListener(buttonId) {
  let clicks = 0;
  document.getElementById(buttonId).addEventListener("click", () => {
    clicks++;
    console.log(`按鈕被點(diǎn)擊了 ${clicks} 次`);
  });
}

attachListener("myButton");

即使 attachListener() 已執(zhí)行完,事件回調(diào)依舊能訪問和更新 clicks。

常見閉包誤區(qū)

  • 誤區(qū)一:以為閉包會(huì)復(fù)制變量 閉包其實(shí)保存的是變量的引用,變量變了閉包看到的也變(這也是循環(huán)陷阱的根源)。
  • 誤區(qū)二:閉包導(dǎo)致內(nèi)存泄漏 如果閉包引用了大型對(duì)象,可能阻止垃圾回收,導(dǎo)致內(nèi)存泄漏。

示例:

function createLeakyFunction() {
  let hugeObject = new Array(1000000).fill("??");
  return () => console.log(hugeObject.length);
}

const leaky = createLeakyFunction();
// hugeObject 仍在內(nèi)存中

解決辦法是及時(shí)釋放引用:

function createLeakyFunction() {
  let hugeObject = new Array(1000000).fill("??");
  return () => {
    console.log(hugeObject.length);
    hugeObject = null; // 釋放內(nèi)存
  };
}

你真的理解閉包了嗎?

閉包是 JavaScript 中最容易被誤解的概念之一,但一旦掌握,你會(huì)在無數(shù)場(chǎng)景發(fā)現(xiàn)它的身影。

無論是狀態(tài)管理、循環(huán)問題,還是封裝邏輯,閉包都給你強(qiáng)大能力——前提是用得正確。

重點(diǎn)總結(jié)

  • ?? 閉包讓函數(shù)能訪問其外層作用域的變量。
  • ?? 用 var 循環(huán)時(shí)要注意閉包陷阱,優(yōu)先用 let 或 IIFE。
  • ?? 閉包適合實(shí)現(xiàn)私有變量、事件監(jiān)聽狀態(tài)保持等場(chǎng)景。
  • ?? 留意閉包持有大對(duì)象引用,避免內(nèi)存泄漏。

現(xiàn)在,去寫更干凈、更聰明的 JavaScript 吧!??


責(zé)任編輯:武曉燕 來源: 大遷世界
相關(guān)推薦

2020-08-12 07:48:11

鏈表單向鏈結(jié)點(diǎn)

2020-08-11 08:13:46

微服務(wù)

2010-09-09 15:05:27

2025-08-18 01:15:00

2020-03-11 08:19:27

JavaScript閉包開發(fā)

2010-06-23 10:24:42

Javascript閉

2009-08-08 09:11:25

Windows 7MSDN版

2017-12-12 09:18:38

DevOpsIT管理系統(tǒng)

2009-10-09 16:43:25

2010-07-07 09:28:25

云計(jì)算虛擬化

2019-05-05 09:24:09

KafkaTopicPartition

2021-03-09 07:37:42

技術(shù)Promise測(cè)試

2019-08-13 09:29:14

Kafka運(yùn)營(yíng)數(shù)據(jù)

2020-03-12 15:00:44

JavaSpring依賴

2011-04-29 09:51:05

投影機(jī)

2019-07-15 16:35:43

MySQL索引阿里

2025-03-27 10:13:03

2011-03-21 15:50:13

上網(wǎng)行為管理百卓網(wǎng)絡(luò)

2020-08-13 10:15:34

MySQL數(shù)據(jù)庫(kù)面試

2014-06-26 11:14:35

Google IO 2014
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)