溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

JavaScript閉包如何理解

發(fā)布時間:2022-02-18 09:39:55 來源:億速云 閱讀:146 作者:iii 欄目:web開發(fā)

這篇“JavaScript閉包如何理解”文章的知識點大部分人都不太理解,所以小編給大家總結(jié)了以下內(nèi)容,內(nèi)容詳細(xì),步驟清晰,具有一定的借鑒價值,希望大家閱讀完這篇文章能有所收獲,下面我們一起來看看這篇“JavaScript閉包如何理解”文章吧。

JavaScript閉包如何理解

1.閉包自結(jié)

閉包概念:

函數(shù)執(zhí)?后返回結(jié)果是?個內(nèi)部函數(shù),并被外部變量所引?,如果內(nèi)部函數(shù)持有被執(zhí)?函數(shù)作?域的變量,即形成了閉包。可以在內(nèi)部函數(shù)訪問到外部函數(shù)作?域。

使?閉包,?可以讀取函數(shù)中的變量,?可以將函數(shù)中的變量存儲在內(nèi)存 中,保護(hù)變量不被污染。?正因閉包會把函數(shù)中的變量值存儲在內(nèi)存中,會對內(nèi)存有消耗,所以不能濫?閉包,否則會影響??性能,造成內(nèi)存泄漏。當(dāng)不需要使?閉包時,要及時釋放內(nèi)存,可將內(nèi)層函數(shù)對象的變量賦值為null。

閉包特點:一個外函數(shù)生成的多個閉包內(nèi)存空間彼此獨立。

閉包應(yīng)用場景:

  1. 在內(nèi)存中維持變量:如果緩存數(shù)據(jù)、柯里化  

  2. 保護(hù)函數(shù)內(nèi)的變量安全:如迭代器、生成器。

缺點:閉包會導(dǎo)致原有的作用域鏈不釋放,造成內(nèi)存的泄漏。

  1. 內(nèi)存消耗有負(fù)?影響。因內(nèi)部函數(shù)保存了對外部變量的引?,導(dǎo)致?法被垃圾回收,增?內(nèi)存使?量,所以使? 不當(dāng)會導(dǎo)致內(nèi)存泄漏

  2. 對處理速度具有負(fù)?影響。閉包的層級決定了引?的外部變量在查找時經(jīng)過的作?域鏈?度

  3. 可能獲取到意外的值(captured value)

優(yōu)點:

  1. 可以從內(nèi)部函數(shù)訪問外部函數(shù)的作?域中的變量,且訪問到的變量?期駐扎在內(nèi)存中,可供之后使?

  2. 避免變量污染全局

  3. 把變量存到獨?的作?域,作為私有成員存在


2.閉包概念

一個函數(shù)和對其周圍狀態(tài)(lexical environment,詞法環(huán)境)的引用捆綁在一起(或者說函數(shù)被引用包圍),這樣的組合就是閉包(closure)。也就是說,閉包讓你可以在一個內(nèi)層函數(shù)中訪問到其外層函數(shù)的作用域。在 JavaScript 中,每當(dāng)創(chuàng)建一個函數(shù),閉包就會在函數(shù)創(chuàng)建的同時被創(chuàng)建出來。

詞法作用域

請看下面的代碼:

function init() {
    var name = "Mozilla"; // name 是一個被 init 創(chuàng)建的局部變量
    function displayName() { // displayName() 是內(nèi)部函數(shù),一個閉包
        alert(name); // 使用了父函數(shù)中聲明的變量
    }
    displayName();
}
init();

init() 創(chuàng)建了一個局部變量 name 和一個名為 displayName() 的函數(shù)。displayName() 是定義在 init() 里的內(nèi)部函數(shù),并且僅在 init() 函數(shù)體內(nèi)可用。請注意,displayName() 沒有自己的局部變量。然而,因為它可以訪問到外部函數(shù)的變量,所以 displayName() 可以使用父函數(shù) init() 中聲明的變量 name 。

使用這個 JSFiddle 鏈接運行該代碼后發(fā)現(xiàn), displayName() 函數(shù)內(nèi)的 alert() 語句成功顯示出了變量 name 的值(該變量在其父函數(shù)中聲明)。這個詞法作用域的例子描述了分析器如何在函數(shù)嵌套的情況下解析變量名。詞法(lexical)一詞指的是,詞法作用域根據(jù)源代碼中聲明變量的位置來確定該變量在何處可用。嵌套函數(shù)可訪問聲明于它們外部作用域的變量。


3.從堆棧的角度看待閉包

基本數(shù)據(jù)類型的變量的值一般存在棧內(nèi)存中,基本的數(shù)據(jù)類型: Number 、Boolean、Undefined、String、Null。;而對象類型的變量的值存儲在堆內(nèi)存中,棧內(nèi)存存儲對應(yīng)空間地址。

var a = 1 
//a是一個基本數(shù)據(jù)類型 
var b = {m: 20 } 
//b是一個對象

對應(yīng)內(nèi)存存儲:

JavaScript閉包如何理解

當(dāng)我們執(zhí)行 b={m:30}時,堆內(nèi)存就有新的對象{m:30},棧內(nèi)存的b指向新的空間地址( 指向{m:30} ),而堆內(nèi)存中原來的{m:20}就會被程序引擎垃圾回收掉,節(jié)約內(nèi)存空間。我們知道js函數(shù)也是對象,它也是在堆與棧內(nèi)存中存儲的,我們來看一下轉(zhuǎn)化:

var a = 1;
function fn(){
    var b = 2
    function fn1(){
        console.log(b)
    }
    fn1()
}
fn()

JavaScript閉包如何理解

棧是一種先進(jìn)后出的數(shù)據(jù)結(jié)構(gòu):

  1. 在執(zhí)行fn前,此時我們在全局執(zhí)行環(huán)境(瀏覽器就是window作用域),全局作用域里有個變量a;

  2. 進(jìn)入fn,此時棧內(nèi)存就會push一個fn的執(zhí)行環(huán)境,這個環(huán)境里有變量b和函數(shù)對象fn1,這里可以訪問自身執(zhí)行環(huán)境和全局執(zhí)行環(huán)境所定義的變量

  3. 進(jìn)入fn1,此時棧內(nèi)存就會push 一個fn1的執(zhí)行環(huán)境,這里面沒有定義其他變量,但是我們可以訪問到fn和全局執(zhí)行環(huán)境里面的變量,因為程序在訪問變量時,是向底層棧一個個找(這就是Javascript語言特有的"鏈?zhǔn)阶饔糜?quot;結(jié)構(gòu)(chain scope),如果找到全局執(zhí)行環(huán)境里都沒有對應(yīng)變量,則程序拋出underfined的錯誤。

  4. 隨著fn1()執(zhí)行完畢,fn1的執(zhí)行環(huán)境被杯銷毀,接著執(zhí)行完fn(),fn的執(zhí)行環(huán)境也會被銷毀,只剩全局的執(zhí)行環(huán)境下,現(xiàn)在沒有b變量,和fn1函數(shù)對象了,只有a 和 fn(函數(shù)聲明作用域是window下)

在函數(shù)內(nèi)訪問某個變量是根據(jù)函數(shù)作用域鏈來判斷變量是否存在的,而函數(shù)作用域鏈?zhǔn)浅绦蚋鶕?jù)函數(shù)所在的執(zhí)行環(huán)境棧來初始化的,所以上面的例子,我們在fn1里面打印變量b,根據(jù)fn1的作用域鏈的找到對應(yīng)fn執(zhí)行環(huán)境下的變量b。所以當(dāng)程序在調(diào)用某個函數(shù)時,做了一下的工作:準(zhǔn)備執(zhí)行環(huán)境,初始函數(shù)作用域鏈和arguments參數(shù)對象

我們現(xiàn)在看下閉包例子

function outer() {
     var  a = '變量1'
     var  inner = function () {
            console.info(a)
     }
    return inner    // inner 就是一個閉包函數(shù),因為他能夠訪問到outer函數(shù)的作用域
}
var  inner = outer()   // 獲得inner閉包函數(shù)
inner()   //"變量1"

當(dāng)程序執(zhí)行完var inner = outer(),其實outer的執(zhí)行環(huán)境并沒有被銷毀,因為他里面的變量a仍然被被inner的函數(shù)作用域鏈所引用,當(dāng)程序執(zhí)行完inner(), 這時候,inner和outer的執(zhí)行環(huán)境才會被銷毀調(diào);《JavaScript高級編程》書中建議:由于閉包會攜帶包含它的函數(shù)的作用域,因為會比其他函數(shù)占用更多內(nèi)容,過度使用閉包,會導(dǎo)致內(nèi)存占用過多。

4.閉包的共享變量問題

下面通過outer外函數(shù)和inner內(nèi)函數(shù)來講解閉包的共享變量問題。

同一個外函數(shù)生成的多個閉包是獨立空間還是共享空間如何判斷?請先看實例

//第一種情況 調(diào)用時給外函數(shù)傳入變量值
function outer(name){
    return function(){
        console.log(name)
    }
}

f1 = outer('yang')
f2 = outer('fang')

console.log(f1.toString())
f1() //yang 
f2() //fang
f1() //yang 

//第二種情況:外函數(shù)局部變量值為變化
function count() {
    var arr = [];
    for (var i=1; i<=3; i++) {
        arr.push(function () {
            return i * i;
        });
    }
    return arr;
}

var results = count();
var f1 = results[0];  //16
var f2 = results[1];  //16
var f3 = results[2];  //16
console.log(f1 )

//第三種情況:外函數(shù)的局部變量值變化。
function test(){
    var i = 0;
    return function(){
       console.log(i++)
    }
}; 
var a = test();
var b = test();
//依次執(zhí)行a,a,b,控制臺會輸出什么呢?0 1 0  
//b為什么不是2
a();a();b();

同一個外函數(shù)生成的多個閉包是獨立空間還是共享空間如何判斷?

  1. 第一種情況說明多次調(diào)用外函數(shù)生成的不同閉包函數(shù)沒有共享name變量

  2. 第二種情況說明外函數(shù)內(nèi)部循環(huán)生成的多個內(nèi)函數(shù)共享 i 局部變量

  3. 第三種情況說明a 、b為兩個 不同閉包 函數(shù),同一閉包函數(shù) a 多次調(diào)用 共享 i 變量,a b之間不共享。

可以總結(jié)出記住三個閉包共享變量的原則

  1. 調(diào)用外函數(shù),就會生成內(nèi)函數(shù)和外函數(shù)的局部變量組成的閉包。每調(diào)用一次生成一個閉包函數(shù)。不同閉包函數(shù)之間內(nèi)存空間彼此獨立。

  2. 調(diào)用同一個閉包函數(shù)多次,共享內(nèi)存空間,即外函數(shù)的局部變量值。

  3. 第二種情況for循環(huán)。沒有調(diào)用外函數(shù),只是將內(nèi)函數(shù)存到了數(shù)組中,故并沒有生成3個獨立的閉包函數(shù)。而是3個內(nèi)函數(shù)共享一個外函數(shù)局部變量,即3個內(nèi)函數(shù)和外函數(shù)局部變量組成了一個整體的閉包環(huán)境。

簡記:調(diào)用一次外函數(shù),生成一個獨立的閉包環(huán)境;外函數(shù)內(nèi)部生成多個內(nèi)函數(shù),那么多個內(nèi)函數(shù)共用一個閉包環(huán)境。


5.閉包應(yīng)用場景

應(yīng)用場景主要就兩個

  • 在內(nèi)存中維持變量:如果緩存數(shù)據(jù)、柯里化  

  • 保護(hù)函數(shù)內(nèi)的變量安全:如迭代器、生成器。

場景一:保存局部變量在內(nèi)存中

閉包很有用,因為它允許將函數(shù)與其所操作的某些數(shù)據(jù)(環(huán)境)關(guān)聯(lián)起來。這顯然類似于面向?qū)ο缶幊?/strong>。在面向?qū)ο缶幊讨校瑢ο笤试S我們將某些數(shù)據(jù)(對象的屬性)與一個或者多個方法相關(guān)聯(lián)。

因此,通常你使用只有一個方法的對象的地方,都可以使用閉包。

在 Web 中,你想要這樣做的情況特別常見。大部分我們所寫的 JavaScript 代碼都是基于事件的 — 定義某種行為,然后將其添加到用戶觸發(fā)的事件之上(比如點擊或者按鍵)。我們的代碼通常作為回調(diào):為響應(yīng)事件而執(zhí)行的函數(shù)。

假如,我們想在頁面上添加一些可以調(diào)整字號的按鈕。一種方法是以像素為單位指定 body 元素的 font-size,然后通過相對的 em 單位設(shè)置頁面中其它元素(例如header)的字號:

body {
  font-family: Helvetica, Arial, sans-serif;
  font-size: 12px;
}
h2 {
  font-size: 1.5em;
}
h3 {
  font-size: 1.2em;
}

我們的文本尺寸調(diào)整按鈕可以修改 body 元素的 font-size 屬性,由于我們使用相對單位,頁面中的其它元素也會相應(yīng)地調(diào)整。

以下是 JavaScript:

function makeSizer(size) {
  return function() {
    document.body.style.fontSize = size + 'px';
  };
}

var size12 = makeSizer(12);
var size14 = makeSizer(14);
var size16 = makeSizer(16);

size12,size14 和 size16 三個函數(shù)將分別把 body 文本調(diào)整為 12,14,16 像素。我們可以將它們分別添加到按鈕的點擊事件上。如下所示:

document.getElementById('size-12').onclick = size12;
document.getElementById('size-14').onclick = size14;
document.getElementById('size-16').onclick = size16;
<a href="#" id="size-12">12</a>
<a href="#" id="size-14">14</a>
<a href="#" id="size-16">16</a>

場景二:用閉包模擬私有方法,保護(hù)局部變量

編程語言中,比如 Java,是支持將方法聲明為私有的,即它們只能被同一個類中的其它方法所調(diào)用。

而 JavaScript 沒有這種原生支持,但我們可以使用閉包來模擬私有方法。私有方法不僅僅有利于限制對代碼的訪問:還提供了管理全局命名空間的強大能力,避免非核心的方法弄亂了代碼的公共接口部分。

下面的示例展現(xiàn)了如何使用閉包來定義公共函數(shù),并令其可以訪問私有函數(shù)和變量。這個方式也稱為 模塊模式(module pattern):

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

console.log(Counter.value()); /* logs 0 */
Counter.increment();
Counter.increment();
console.log(Counter.value()); /* logs 2 */
Counter.decrement();
console.log(Counter.value()); /* logs 1 */

可以將上面的代碼拆分成兩部分:(function(){}) () 。第1個() 是一個表達(dá)式,而這個表達(dá)式本身是一個匿名函數(shù),所以在這個表達(dá)式后面加 () 就表示執(zhí)行這個匿名函數(shù)。

在之前的示例中,每個閉包都有它自己的詞法環(huán)境;而這次我們只創(chuàng)建了一個詞法環(huán)境,為三個函數(shù)所共享:Counter.increment,Counter.decrement 和 Counter.value。

該共享環(huán)境創(chuàng)建于一個立即執(zhí)行的匿名函數(shù)體內(nèi)。這個環(huán)境中包含兩個私有項:名為 privateCounter 的變量和名為 changeBy 的函數(shù)。這兩項都無法在這個匿名函數(shù)外部直接訪問。必須通過匿名函數(shù) 返回的三個公共函數(shù)訪問。

這三個公共函數(shù)是共享同一個環(huán)境的閉包。多虧 JavaScript 的詞法作用域,它們都可以訪問 privateCounter 變量和 changeBy 函數(shù)。

你應(yīng)該注意到我們定義了一個匿名函數(shù),用于創(chuàng)建一個計數(shù)器。我們立即執(zhí)行了這個匿名函數(shù),并將他的值賦給了變量Counter。我們可以把這個函數(shù)儲存在另外一個變量makeCounter中,并用他來創(chuàng)建多個計數(shù)器。
var makeCounter = function() {
  var privateCounter = 0;
  function changeBy(val) {
    privateCounter += val;
  }
  return {
    increment: function() {
      changeBy(1);
    },
    decrement: function() {
      changeBy(-1);
    },
    value: function() {
      return privateCounter;
    }
  }  
};

var Counter1 = makeCounter();
var Counter2 = makeCounter();
console.log(Counter1.value()); /* logs 0 */
Counter1.increment();
Counter1.increment();
console.log(Counter1.value()); /* logs 2 */
Counter1.decrement();
console.log(Counter1.value()); /* logs 1 */
console.log(Counter2.value()); /* logs 0 */

請注意兩個計數(shù)器 Counter1 和 Counter2 是如何維護(hù)它們各自的獨立性的。每個閉包都是引用自己詞法作用域內(nèi)的變量 privateCounter 。

每次調(diào)用其中一個計數(shù)器時,通過改變這個變量的值,會改變這個閉包的詞法環(huán)境。然而在一個閉包內(nèi)對變量的修改,不會影響到另外一個閉包中的變量。

以這種方式使用閉包,提供了許多與面向?qū)ο缶幊滔嚓P(guān)的好處 —— 特別是數(shù)據(jù)隱藏和封裝。


6.循環(huán)中創(chuàng)建閉包的一個常見錯誤

在 ECMAScript 2015 引入 let 關(guān)鍵字 之前,在循環(huán)中有一個常見的閉包創(chuàng)建錯誤。參考下面的示例:

<p id="help">Helpful notes will appear here</p>
<p>E-mail: <input type="text" id="email" name="email"></p>
<p>Name: <input type="text" id="name" name="name"></p>
<p>Age: <input type="text" id="age" name="age"></p>
function showHelp(help) {
  document.getElementById('help').innerHTML = help;
}

function setupHelp() {
  var helpText = [
      {'id': 'email', 'help': 'Your e-mail address'},
      {'id': 'name', 'help': 'Your full name'},
      {'id': 'age', 'help': 'Your age (you must be over 16)'}
    ];

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

setupHelp();
//一、將function直接返回,會發(fā)生閉包
 //二、將函數(shù)賦值給一個變量,此變量函數(shù)外部使用,此時也是閉包。比如,數(shù)組、多個變量等。 舉例下面也是閉包情況。
 var arr = []
 for (var i = 0; i < 10; i++) {
    arr[i] = function(){console.log(i)}
  }
  arr[6]()此時也是閉包,將十個匿名函數(shù)+i組成了一個閉包返回。

數(shù)組 helpText 中定義了三個有用的提示信息,每一個都關(guān)聯(lián)于對應(yīng)的文檔中的input 的 ID。通過循環(huán)這三項定義,依次為相應(yīng)input添加了一個 onfocus  事件處理函數(shù),以便顯示幫助信息。

運行這段代碼后,您會發(fā)現(xiàn)它沒有達(dá)到想要的效果。無論焦點在哪個input上,顯示的都是關(guān)于年齡的信息。

原因是賦值給 onfocus 的是閉包。這些閉包是由他們的函數(shù)定義和在 setupHelp 作用域中捕獲的環(huán)境所組成的。這三個閉包在循環(huán)中被創(chuàng)建,但他們共享了同一個詞法作用域,在這個作用域中存在一個變量item。這是因為變量item使用var進(jìn)行聲明,由于變量提升,所以具有函數(shù)作用域。當(dāng)onfocus的回調(diào)執(zhí)行時,item.help的值被決定。由于循環(huán)在事件觸發(fā)之前早已執(zhí)行完畢,變量對象item(被三個閉包所共享)已經(jīng)指向了helpText的最后一項。

解決這個問題的一種方案是使用更多的閉包:特別是使用前面所述的函數(shù)工廠:

function showHelp(help) {
  document.getElementById('help').innerHTML = help;
}

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

function setupHelp() {
  var helpText = [
      {'id': 'email', 'help': 'Your e-mail address'},
      {'id': 'name', 'help': 'Your full name'},
      {'id': 'age', 'help': 'Your age (you must be over 16)'}
    ];

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

setupHelp();

這段代碼可以如我們所期望的那樣工作。所有的回調(diào)不再共享同一個環(huán)境, makeHelpCallback 函數(shù)為每一個回調(diào)創(chuàng)建一個新的詞法環(huán)境。在這些環(huán)境中,help 指向 helpText 數(shù)組中對應(yīng)的字符串。

另一種方法使用了匿名閉包:

function showHelp(help) {
  document.getElementById('help').innerHTML = help;
}

function setupHelp() {
  var helpText = [
      {'id': 'email', 'help': 'Your e-mail address'},
      {'id': 'name', 'help': 'Your full name'},
      {'id': 'age', 'help': 'Your age (you must be over 16)'}
    ];

  for (var i = 0; i < helpText.length; i++) {
    (function() {
       var item = helpText[i];
       document.getElementById(item.id).onfocus = function() {
         showHelp(item.help);
       }
    })(); // 馬上把當(dāng)前循環(huán)項的item與事件回調(diào)相關(guān)聯(lián)起來
  }
}

setupHelp();

如果不想使用過多的閉包,你可以用ES2015引入的let關(guān)鍵詞:

function showHelp(help) {
  document.getElementById('help').innerHTML = help;
}

function setupHelp() {
  var helpText = [
      {'id': 'email', 'help': 'Your e-mail address'},
      {'id': 'name', 'help': 'Your full name'},
      {'id': 'age', 'help': 'Your age (you must be over 16)'}
    ];

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

setupHelp();

這個例子使用let而不是var,因此每個閉包都綁定了塊作用域的變量,這意味著不再需要額外的閉包。

另一個可選方案是使用 forEach()來遍歷helpText數(shù)組,如下所示:

function showHelp(help) {
  document.getElementById('help').innerHTML = help;
}

function setupHelp() {
  var helpText = [
      {'id': 'email', 'help': 'Your e-mail address'},
      {'id': 'name', 'help': 'Your full name'},
      {'id': 'age', 'help': 'Your age (you must be over 16)'}
    ];

  helpText.forEach(function(text) {
    document.getElementById(text.id).onfocus = function() {
      showHelp(text.help);
    }
  });
}

setupHelp();

7.性能考量

如果不是某些特定任務(wù)需要使用閉包,在其它函數(shù)中創(chuàng)建函數(shù)是不明智的,因為閉包在處理速度和內(nèi)存消耗方面對腳本性能具有負(fù)面影響。

但是如果某個函數(shù)需要不停新建,那么使用閉包保存到內(nèi)存中對性能有好處。

釋放閉包只需要將引用閉包的函數(shù)置為null即可。


8.閉包注意事項

第一:多個內(nèi)函數(shù)引用同一局部變量

function outer() {
      var result = [];
      for (var i = 0; i<10; i++){
        result.[i] = function () {
            console.info(i)
        }
     }
     return result
}

看樣子result每個閉包函數(shù)對打印對應(yīng)數(shù)字,1,2,3,4,...,10, 實際不是,因為每個閉包函數(shù)訪問變量i是outer執(zhí)行環(huán)境下的變量i,隨著循環(huán)的結(jié)束,i已經(jīng)變成10了,所以執(zhí)行每個閉包函數(shù),結(jié)果打印10, 10, ..., 10
怎么解決這個問題呢?

function outer() {
      var result = [];
      for (var i = 0; i<10; i++){
        result.[i] = function (num) {
             return function() {
                   console.info(num);    // 此時訪問的num,是上層函數(shù)執(zhí)行環(huán)境的num,數(shù)組有10個函數(shù)對象,每個對象的執(zhí)行環(huán)境下的number都不一樣
             }
        }(i)
     }
     return result
}

第二: this指向問題

var object = {
     name: ''object",
     getName: function() {
        return function() {
             console.info(this.name)
        }
    }
}
object.getName()()    // underfined
// 因為里面的閉包函數(shù)是在window作用域下執(zhí)行的,也就是說,this指向windows

第三:內(nèi)存泄露問題

function  showId() {
    var el = document.getElementById("app")
    el.onclick = function(){
      aler(el.id)   // 這樣會導(dǎo)致閉包引用外層的el,當(dāng)執(zhí)行完showId后,el無法釋放
    }
}

// 改成下面
function  showId() {
    var el = document.getElementById("app")
    var id  = el.id
    el.onclick = function(){
      aler(id)   // 這樣會導(dǎo)致閉包引用外層的el,當(dāng)執(zhí)行完showId后,el無法釋放
    }
    el = null    // 主動釋放el
}

以上就是關(guān)于“JavaScript閉包如何理解”這篇文章的內(nèi)容,相信大家都有了一定的了解,希望小編分享的內(nèi)容對大家有幫助,若想了解更多相關(guān)的知識內(nèi)容,請關(guān)注億速云行業(yè)資訊頻道。

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI