国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

我從來(lái)不理解JavaScript閉包,但我用了它好多年

這篇具有很好參考價(jià)值的文章主要介紹了我從來(lái)不理解JavaScript閉包,但我用了它好多年。希望對(duì)大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請(qǐng)大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問。

前言

??? 大家好,我是南木元元,熱衷分享有趣實(shí)用的文章,希望大家多多支持,一起進(jìn)步!

????個(gè)人主頁(yè):南木元元

你是否學(xué)習(xí)了很久JavaScript但還沒有搞懂閉包呢?今天就來(lái)聊一下被很多人譽(yù)為JavaScript中最難理解的概念之一的閉包。


目錄

閉包的概念

閉包產(chǎn)生的原因

作用域&作用域鏈

閉包的本質(zhì)

閉包的表現(xiàn)形式

閉包的用途

封裝私有變量

做緩存

閉包的缺點(diǎn)

結(jié)語(yǔ)


閉包的概念

  • 紅寶書(P309)上對(duì)于閉包的定義

閉包指的是那些引用了另一個(gè)函數(shù)作用域中變量的函數(shù),通常是在嵌套函數(shù)中實(shí)現(xiàn)的。

  • MDN對(duì)閉包的定義

閉包是指那些能夠訪問自由變量的函數(shù)。其中自由變量是指在函數(shù)中使用的,但既不是函數(shù)參數(shù)也不是函數(shù)的局部變量的變量。

總結(jié)一下就是,閉包是指有權(quán)訪問另一個(gè)函數(shù)作用域中變量的函數(shù),創(chuàng)建閉包的最常見的方式就是在一個(gè)函數(shù)內(nèi)創(chuàng)建另一個(gè)函數(shù),創(chuàng)建的函數(shù)可以訪問到當(dāng)前函數(shù)的局部變量。

下面就是一個(gè)閉包的例子。

// 外部函數(shù)
function outerFunction() {
  let outerVariable = 'outer';
  // 內(nèi)部函數(shù)
  function innerFunction() {
    console.log(outerVariable);
  }
  
  return innerFunction;
}
  
const innerFunc = outerFunction();
innerFunc(); // outer

在上面的代碼示例中,函數(shù)outerFunction內(nèi)部有一個(gè)innerFunction函數(shù),innerFunction函數(shù)可以訪問到outerFunction函數(shù)中的變量,此時(shí)函數(shù)innerFunction就是一個(gè)閉包。

閉包產(chǎn)生的原因

作用域&作用域鏈

首先需要知道作用域和作用域鏈的概念。

作用域就是變量與函數(shù)的可訪問范圍

在js中,有三種作用域:

  • 全局作用域:變量在整個(gè)全局中都能被訪問到
  • 函數(shù)作用域:變量只能在當(dāng)前函數(shù)內(nèi)被訪問到
  • 塊級(jí)作用域:變量通過ES6中的let和const來(lái)聲明,只能在?對(duì)花括號(hào){ }包裹的塊中訪問

作用域鏈:從當(dāng)前作用域開始一層層往上找某個(gè)變量,如果找到全局作用域還沒找到,就放棄尋找,這種層級(jí)關(guān)系就是作用域鏈。

  • 靜態(tài)作用域

js 采用的是靜態(tài)作用域詞法作用域),即函數(shù)的作用域在函數(shù)定義時(shí)就確定了。

var num = 10;
function f1(){
  console.log(num)
}
function f2(){
  var num  = 20;
  f1()
}
f2();//10

以上代碼的執(zhí)行結(jié)果為10,這段代碼經(jīng)歷了這樣的執(zhí)行過程:

  • f2函數(shù)調(diào)用,f1函數(shù)調(diào)用
  • 在f1函數(shù)作用域內(nèi)查找是否有局部變量num
  • 發(fā)現(xiàn)沒找到,于是根據(jù)書寫位置,向上一層作用域(全局作用域)查找,輸出10

靜態(tài)作用域也稱為詞法作用域,即在詞法分析時(shí)生成的作用域,詞法分析階段,也可以理解為代碼書寫階段,當(dāng)你把函數(shù)書寫到某個(gè)位置,不用執(zhí)行,它的作用域就已經(jīng)確定了。與之相對(duì)的是動(dòng)態(tài)作用域,函數(shù)的作?域在函數(shù)調(diào)?時(shí)才確定,如果采用動(dòng)態(tài)作用域,那么上述結(jié)果為20(如果想深入了解,可以去看這篇文章)。

在了解了js的作用域和作用域鏈后,讓我們來(lái)看看下面這段代碼:

var num = 10;

function fn() {
  var num = 20;
  function fun() {
    console.log(num);//20
  }
  return fun;
}
var x = fn();
x();

上述例子中有三個(gè)作用域:全局作用域、fn的函數(shù)作用域、fun的函數(shù)作用域,它們的關(guān)系如下:

我從來(lái)不理解JavaScript閉包,但我用了它好多年,javascript,javascript,前端

作用域鏈關(guān)系如下:

我從來(lái)不理解JavaScript閉包,但我用了它好多年,javascript,javascript,前端

在這段代碼中,fn的作用域指向有全局作用域和它本身,而fun的作用域指向全局作用域、fn和它本身。而作用域是從最底層向上找,當(dāng)我們?cè)噲D在fun這個(gè)函數(shù)里訪問變量num的時(shí)候,此時(shí)函數(shù)作用域內(nèi)沒有num變量,當(dāng)前作用域找不到,我們需要去上層作用域(fn函數(shù)作用域)找,在這里我們找到了num為20,輸出即可(如果找到全局作用域還沒有的話就會(huì)報(bào)錯(cuò))。

閉包的本質(zhì)

問大家一個(gè)問題:那是不是只有像上述例子一樣返回函數(shù)才算是產(chǎn)生了閉包呢?

其實(shí),閉包產(chǎn)生的本質(zhì)就是:當(dāng)前環(huán)境中存在指向父級(jí)作用域的引用。因此我們還可以這么做:

var fun;
function fn() {
  var num = 2;
  fun = function() {
    console.log(num); //2
  }
}
fn();
fun();

讓fn執(zhí)行,給fun賦值后,等于說現(xiàn)在fun擁有了全局、fn和fun本身這幾個(gè)作用域的訪問權(quán)限,還是自底向上查找,最近是在fn中找到了num,因此輸出2。

在這里是外面的變量fun存在著父級(jí)作用域的引用,因此產(chǎn)生了閉包,形式變了,本質(zhì)沒有改變。

閉包的表現(xiàn)形式

明白了本質(zhì)后,那我們思考下,實(shí)際場(chǎng)景中,閉包是如何體現(xiàn)的呢?

  • 返回一個(gè)函數(shù)(上面已經(jīng)舉例)
  • 作為函數(shù)參數(shù)傳遞
var a = 1;
function foo(){
  var a = 2;
  function baz(){
    console.log(a);
  }
  bar(baz);
}
function bar(fn){
  // 這就是閉包
  fn();
}
// 輸出2,而不是1
foo();
  • 定時(shí)器、事件監(jiān)聽或者任何異步中,只要使用了回調(diào)函數(shù),實(shí)際上就是在使用閉包。

比如以下的閉包保存的僅僅是window和當(dāng)前作用域。

// 定時(shí)器
setTimeout(function timeHandler(){
  console.log('111');
},100)

// 事件監(jiān)聽
$('#btn').click(function(){
  console.log('222');
})
  • IIFE(立即執(zhí)行函數(shù)表達(dá)式)創(chuàng)建閉包,保存了全局作用域window和當(dāng)前的函數(shù)作用域,因此可以使用全局的變量。
var a = 2;
(function IIFE(){
  // 輸出2
  console.log(a);
})();

現(xiàn)在,你是否會(huì)感嘆一句:好家伙,原來(lái)我用了閉包這么多年!

閉包的用途

閉包有兩個(gè)常用的用途:

  • 封裝私有變量
  • 做緩存

封裝私有變量

閉包可以使我們?cè)诤瘮?shù)外部能夠訪問到函數(shù)內(nèi)部的變量。通過使用閉包,可以通過在外部調(diào)用閉包函數(shù),從而在外部訪問到函數(shù)內(nèi)部的變量,可以使用這種方法來(lái)創(chuàng)建私有變量,以防止其被外部訪問和修改。

在下面這個(gè)例子中,調(diào)用函數(shù),輸出的結(jié)果都是1,但是我們的代碼效果是想讓count每次加一。

function add() {
    let count = 0;
    count++;
    console.log(count);
}
add()   //輸出1
add()   //輸出1
add()   //輸出1

一種顯而易見的方法是將count提到函數(shù)體外,作為全局變量。這么做當(dāng)然是可以解決問題,但是在實(shí)際開發(fā)中,一個(gè)項(xiàng)目由多人共同開發(fā),你不清楚別人定義的變量名稱是什么,很容易沖突,有什么其他的辦法可以解決這個(gè)問題呢?

function add(){
    let count = 0
    function a(){
        count++
        console.log(count);
    }
    return a
}
var res = add() 
res() //1 
res() //2
res() //3

答案是用閉包。在上面的代碼示例中,add函數(shù)返回了一個(gè)閉包a,其中包含了count變量。由于count只在add函數(shù)內(nèi)部定義,因此外部無(wú)法直接訪問它。但是,由于a函數(shù)引用了count變量,因此count變量的值可以在閉包內(nèi)部被修改和訪問。這種方式可以用于封裝一些私有的數(shù)據(jù)和邏輯。

做緩存

函數(shù)一旦被執(zhí)行完畢,其內(nèi)存就會(huì)被銷毀。而閉包可以使已經(jīng)運(yùn)行結(jié)束的函數(shù)上下文中的變量對(duì)象繼續(xù)留在內(nèi)存中,因?yàn)殚]包函數(shù)保留了這個(gè)變量對(duì)象的引用,所以這個(gè)變量對(duì)象不會(huì)被回收。

function foo(){
  var myName ='張三';
  let test = 1;
  var innerBar={
      getName: function(){
          console.log(test);
          return myName;
      },
      setName:function(newName){
          myName = newName;
      }
  }
  return innerBar;
}
var bar = foo();
console.log(bar.getName()); //1 張三
bar.setName('李四');
console.log(bar.getName()); //1 李四

這里var bar = foo() 執(zhí)行完后本來(lái)應(yīng)該被銷毀,但是因?yàn)樾纬闪碎]包,所以導(dǎo)致foo執(zhí)行上下文沒有被銷毀干凈,被引用了的變量myName、test沒被銷毀,閉包里存放的就是變量myName、test,這個(gè)閉包就像是setName、getName的專屬背包,setName、getName依然可以使用foo執(zhí)行上下文中的test和myName。

閉包的應(yīng)用是非常廣泛的,比如常見的防抖和節(jié)流等其實(shí)也都是閉包的應(yīng)用。

閉包的缺點(diǎn)

閉包也存在著一個(gè)潛在的問題,由于閉包會(huì)引用外部函數(shù)的變量,但是這些變量在外部函數(shù)執(zhí)行完畢后沒有被釋放,那么這些變量會(huì)一直存在于內(nèi)存中,這可能會(huì)帶來(lái)內(nèi)存泄漏問題,因此,需要及時(shí)釋放閉包,即手動(dòng)調(diào)用閉包函數(shù),并將其返回值賦值為null,這樣可以讓閉包中的變量及時(shí)被垃圾回收器回收。

結(jié)語(yǔ)

本文主要介紹了被譽(yù)為JavaScript中最難理解的概念之一的閉包,閉包的表現(xiàn)形式多樣、應(yīng)用廣泛,日常開發(fā)中其實(shí)都有閉包的身影,在實(shí)際的開發(fā)過程中,合理地使用閉包可以幫助我們更加高效地編寫代碼,提高程序的性能和可維護(hù)性。

??如果此文對(duì)你有幫助的話,歡迎??關(guān)注、??點(diǎn)贊、?收藏、??評(píng)論,支持一下博主~?文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-751652.html

到了這里,關(guān)于我從來(lái)不理解JavaScript閉包,但我用了它好多年的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來(lái)自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場(chǎng)。本站僅提供信息存儲(chǔ)空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請(qǐng)注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請(qǐng)點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • JavaScript閉包詳細(xì)介紹

    閉包是指有權(quán)訪問另一個(gè)函數(shù)作用域中的變量的函數(shù),創(chuàng)建閉包的常見方式是讓一個(gè)內(nèi)嵌函數(shù)訪問其外部(父級(jí))函數(shù)的變量,即使外部函數(shù)已經(jīng)執(zhí)行完畢,其變量仍然存在于內(nèi)存中。閉包的主要特點(diǎn)是它可以“記住”外部函數(shù)的變量。 變量持久化: 閉包能夠保持對(duì)外部作

    2024年02月20日
    瀏覽(21)
  • 9 JavaScript閉包

    9 JavaScript閉包

    9 閉包 我們都知道,函數(shù)里是可以訪問函數(shù)外的全局變量,而函數(shù)外不能訪問函數(shù)內(nèi)的局部變量,如下: 執(zhí)行結(jié)果: 執(zhí)行結(jié)果: 之所以出現(xiàn)這樣的情況,就是因?yàn)楹瘮?shù)內(nèi)定義的變量為局部變量,函數(shù)外定義的變量為全局變量(不同于windows)。在函數(shù)內(nèi)部可以訪問到全局變量,

    2024年02月12日
    瀏覽(24)
  • JavaScript 作用域與閉包

    本文內(nèi)容學(xué)習(xí)于:后盾人 (houdunren.com) 1.作用域 1)函數(shù)被執(zhí)行后其環(huán)境變量將從內(nèi)存中刪除。下面函數(shù)在每次執(zhí)行后將刪除函數(shù)內(nèi)部的 total 變量。 ?function count() { ????????let total = 0; } count (); 2)函數(shù)每次調(diào)用都會(huì)創(chuàng)建一個(gè)新作用域 3)如果子函數(shù)被使用時(shí)父級(jí)環(huán)境將被保留

    2024年02月14日
    瀏覽(25)
  • JavaScript閉包漏洞與修補(bǔ)措施

    JavaScript閉包漏洞與修補(bǔ)措施

    請(qǐng)先看下面一段代碼 可以看出,這是一段很典型的js閉包代碼,可以通過obj調(diào)用get方法傳一個(gè)參數(shù),如果傳的是a就可以得到閉包內(nèi)的對(duì)象sonObj.a 如下,正確的獲取到了sonObj的屬性a 這是一個(gè)典型的閉包場(chǎng)景,這樣做的目的是為了屏蔽這個(gè)obj,不讓外邊直接訪問它,只能讀取它的某一個(gè)屬

    2024年02月10日
    瀏覽(20)
  • JavaScript高級(jí):閉包與作用域

    在 JavaScript 的世界里,閉包是一個(gè)令人著迷且神秘的概念,它為我們提供了一種強(qiáng)大的能力,能夠在函數(shù)內(nèi)部捕獲并保留外部作用域的變量。本文將詳細(xì)解釋閉包的概念與應(yīng)用,帶你揭開 JavaScript 的神秘面紗,通俗易懂地理解閉包的奧秘。 1. 作用域與閉包的關(guān)系 作用域是指

    2024年02月13日
    瀏覽(26)
  • JavaScript(函數(shù),作用域和閉包)

    JavaScript(函數(shù),作用域和閉包)

    類似于Java中的方法,是完成特定任務(wù)的代碼語(yǔ)句塊 特點(diǎn) 使用更簡(jiǎn)單 不用定義屬于某個(gè)類,直接調(diào)用執(zhí)行 分類 系統(tǒng)函數(shù) 自定義函數(shù) 1.將字符串轉(zhuǎn)換為整型數(shù)字 js示例1 從下標(biāo)為0起,依次判斷每個(gè)字符是否可以轉(zhuǎn)換為一個(gè)有效數(shù)字 如果不是有效數(shù)字,則返回NaN,不再繼續(xù)執(zhí)

    2024年02月10日
    瀏覽(25)
  • 【面試高頻】JavaScript作用域、閉包、變量提升

    【面試高頻】JavaScript作用域、閉包、變量提升

    目錄 前言 一、作用域 1. 局部作用域 2. 全局作用域 二、作用域鏈 三、閉包 1. 閉包是什么 2. 閉包的運(yùn)用 JavaScript 中的作用域、閉包和變量提升是 JavaScript 中的重要概念,也是面試高頻考點(diǎn)。 作用域規(guī)定了變量的可見性和生命周期,閉包通過捕獲自由變量的方式延長(zhǎng)了變量的

    2024年02月12日
    瀏覽(25)
  • Go的閉包理解

    筆記倉(cāng)庫(kù):gitee.com/xiaoyinhui 一點(diǎn)點(diǎn)筆記,以便以后翻閱。

    2024年02月22日
    瀏覽(26)
  • 學(xué)習(xí)并深入理解閉包

    學(xué)習(xí)并深入理解閉包

    前言 學(xué)習(xí)閉包前,先學(xué)點(diǎn)別的。 程序執(zhí)行時(shí): 1.編譯階段 創(chuàng)建變量對(duì)象GO,包括變量和函數(shù)作用域裝在一塊內(nèi)存中。但是沒有賦值,變量都是undefined,函數(shù):0xxx 2.創(chuàng)建執(zhí)行上下文 里面有VO對(duì)應(yīng)ao(函數(shù)里的變量,沒執(zhí)行,undefined,執(zhí)行,被賦值) 3.代碼執(zhí)行 函數(shù)里的變量賦值

    2024年02月08日
    瀏覽(18)
  • 閉包的理解

    閉包的理解

    變量的私有化。一個(gè)函數(shù)內(nèi)的變量,隨著函數(shù)的執(zhí)行完畢,對(duì)于的變量也會(huì)隨著銷毀,閉包可以讓變量在函數(shù)執(zhí)行完畢之后不必銷毀,通常將這個(gè)變量通過匿名函數(shù)的形式return出去,這個(gè)變量只能被訪問,不能被修改。 打印的結(jié)果: 可以看出a變量每次都遞增了1,從這個(gè)結(jié)論來(lái)看也可以

    2024年02月09日
    瀏覽(16)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請(qǐng)作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包