亚洲中字慕日产2020,大陆极品少妇内射AAAAAA,无码av大香线蕉伊人久久,久久精品国产亚洲av麻豆网站

資訊專欄INFORMATION COLUMN

深入淺出Javascript閉包

tyheist / 949人閱讀

摘要:如果有時(shí)需要得到函數(shù)內(nèi)的局部變量。上面代碼中,函數(shù)就在函數(shù)內(nèi)部,這時(shí)內(nèi)部的所有局部變量,對(duì)都是可見(jiàn)的。所謂內(nèi)存泄漏指任何對(duì)象在您不再擁有或需要它之后仍然存在。閉包不能濫用,否則會(huì)導(dǎo)致內(nèi)存泄露,影響網(wǎng)頁(yè)的性能。

一、引子

閉包(closure)是 Javascript 語(yǔ)言的一個(gè)難點(diǎn),面試時(shí)常被問(wèn)及,也是它的特色,很多高級(jí)應(yīng)用都要依靠閉包實(shí)現(xiàn)。本文盡可能用簡(jiǎn)單易懂的話,講清楚閉包的概念、形成條件及其常見(jiàn)的面試題。

我們先來(lái)看一個(gè)例子:

var n = 999;
function f1() {
console.log(n);
}
f1() // 999

上面代碼中,函數(shù)f1可以讀取全局變量n。但是,函數(shù)外部無(wú)法讀取函數(shù)內(nèi)部聲明的變量。

function f1() {
var n = 999;
}
console.log(n)
// Uncaught ReferenceError: n is not defined

上面代碼中,函數(shù)f1內(nèi)部聲明的變量n,函數(shù)外是無(wú)法讀取的。

如果有時(shí)需要得到函數(shù)內(nèi)的局部變量。正常情況下,這是辦不到的,只有通過(guò)變通方法才能實(shí)現(xiàn)。那就是在函數(shù)的內(nèi)部,再定義一個(gè)函數(shù)。

function f1() {
var n = 999;
function f2() {
  console.log(n); // 999
 }
}

上面代碼中,函數(shù)f2就在函數(shù)f1內(nèi)部,這時(shí)f1內(nèi)部的所有局部變量,對(duì)f2都是可見(jiàn)的。既然f2可以讀取f1的局部變量,那么只要把f2作為返回值,我們不就可以在f1外部讀取它的內(nèi)部變量了嗎!

二、閉包是什么

我們可以對(duì)上面代碼進(jìn)行如下修改:

   function f1(){
   var a = 999;
   function f2(){
    console.log(a);
   }
   return f2; // f1返回了f2的引用
   }
   var result = f1(); // result就是f2函數(shù)了
   result();  // 執(zhí)行result,全局作用域下沒(méi)有a的定義,
         //但是函數(shù)閉包,能夠把定義函數(shù)的時(shí)候的作用域一起記住,輸出999            

上面代碼中,函數(shù)f1的返回值就是函數(shù)f2,由于f2可以讀取f1的內(nèi)部變量,所以就可以在外部獲得f1的內(nèi)部變量了。

閉包就是函數(shù)f2,即能夠讀取其他函數(shù)內(nèi)部變量的函數(shù)。由于在JavaScript語(yǔ)言中,只有函數(shù)內(nèi)部的子函數(shù)才能讀取內(nèi)部變量,因此可以把閉包簡(jiǎn)單理解成“定義在一個(gè)函數(shù)內(nèi)部的函數(shù)”。閉包最大的特點(diǎn),就是它可以“記住”誕生的環(huán)境,比如f2記住了它誕生的環(huán)境f1,所以從f2可以得到f1的內(nèi)部變量。在本質(zhì)上,閉包就是將函數(shù)內(nèi)部和函數(shù)外部連接起來(lái)的一座橋梁。

那到底什么是閉包呢?

當(dāng)函數(shù)可以記住并訪問(wèn)所在的詞法作用域,即使函數(shù)是在當(dāng)前詞法作用域之外執(zhí)行,這就產(chǎn)生了閉包。 ----《你不知道的Javascript上卷》

我個(gè)人理解,閉包就是函數(shù)中的函數(shù)(其他語(yǔ)言不能函數(shù)再套函數(shù)),里面的函數(shù)可以訪問(wèn)外面函數(shù)的變量,外面的變量的是這個(gè)內(nèi)部函數(shù)的一部分。

閉包形成的條件

函數(shù)嵌套

內(nèi)部函數(shù)引用外部函數(shù)的局部變量

三、閉包的特性

每個(gè)函數(shù)都是閉包,每個(gè)函數(shù)天生都能夠記憶自己定義時(shí)所處的作用域環(huán)境。把一個(gè)函數(shù)從它定義的那個(gè)作用域,挪走,運(yùn)行。這個(gè)函數(shù)居然能夠記憶住定義時(shí)的那個(gè)作用域。不管函數(shù)走到哪里,定義時(shí)的作用域就帶到了哪里。接下來(lái)我們用兩個(gè)例子來(lái)說(shuō)明這個(gè)問(wèn)題:

//例題1
var inner;
function outer(){
var a=250;
inner=function(){
alert(a);//這個(gè)函數(shù)雖然在外面執(zhí)行,但能夠記憶住定義時(shí)的那個(gè)作用域,a是250
  }
}
outer();
var a=300;
inner();//一個(gè)函數(shù)在執(zhí)行的時(shí)候,找閉包里面的變量,不會(huì)理會(huì)當(dāng)前作用域。
//例題2
function outer(x){
  function inner(y){
  console.log(x+y);
  }
return inner;
}
var inn=outer(3);//數(shù)字3傳入outer函數(shù)后,inner函數(shù)中x便會(huì)記住這個(gè)值
inn(5);//當(dāng)inner函數(shù)再傳入5的時(shí)候,只會(huì)對(duì)y賦值,所以最后彈出8
四、閉包的內(nèi)存泄漏

棧內(nèi)存提供一個(gè)執(zhí)行環(huán)境,即作用域,包括全局作用域和私有作用域,那他們什么時(shí)候釋放內(nèi)存的?

全局作用域----只有當(dāng)頁(yè)面關(guān)閉的時(shí)候全局作用域才會(huì)銷毀

私有的作用域----只有函數(shù)執(zhí)行才會(huì)產(chǎn)生

一般情況下,函數(shù)執(zhí)行會(huì)形成一個(gè)新的私有的作用域,當(dāng)私有作用域中的代碼執(zhí)行完成后,我們當(dāng)前作用域都會(huì)主動(dòng)的進(jìn)行釋放和銷毀。但當(dāng)遇到函數(shù)執(zhí)行返回了一個(gè)引用數(shù)據(jù)類型的值,并且在函數(shù)的外面被一個(gè)其他的東西給接收了,這種情況下一般形成的私有作用域都不會(huì)銷毀

如下面這種情況:

function fn(){
var num=100;
return function(){
  }
}
var f=fn();//fn執(zhí)行形成的這個(gè)私有的作用域就不能再銷毀了

也就是像上面這段代碼,fn函數(shù)內(nèi)部的私有作用域會(huì)被一直占用的,發(fā)生了內(nèi)存泄漏。所謂內(nèi)存泄漏指任何對(duì)象在您不再擁有或需要它之后仍然存在。閉包不能濫用,否則會(huì)導(dǎo)致內(nèi)存泄露,影響網(wǎng)頁(yè)的性能。閉包使用完了后,要立即釋放資源,將引用變量指向null

接下來(lái)我們看下有關(guān)于內(nèi)存泄漏的一道經(jīng)典面試題:

  function?outer(){
  var?num=0;//內(nèi)部變量
  return?function?add(){//通過(guò)return返回add函數(shù),就可以在outer函數(shù)外訪問(wèn)了
  num++;//內(nèi)部函數(shù)有引用,作為add函數(shù)的一部分了
  console.log(num);
  };
 }
  var?func1=outer();
  func1();//實(shí)際上是調(diào)用add函數(shù),?輸出1
  func1();//輸出2 因?yàn)閛uter函數(shù)內(nèi)部的私有作用域會(huì)一直被占用
  var?func2=outer();
  func2();//?輸出1??每次重新引用函數(shù)的時(shí)候,閉包是全新的。
  func2();//?輸出2??
五、閉包的作用

1.可以讀取函數(shù)內(nèi)部的變量。

2.可以使變量的值長(zhǎng)期保存在內(nèi)存中,生命周期比較長(zhǎng)。因此不能濫用閉包,否則會(huì)造成網(wǎng)頁(yè)的性能問(wèn)題

3.可以用來(lái)實(shí)現(xiàn)JS模塊。

JS模塊:具有特定功能的js文件,將所有的數(shù)據(jù)和功能都封裝在一個(gè)函數(shù)內(nèi)部(私有的),只向外暴露一個(gè)包信n個(gè)方法的對(duì)象或函數(shù),模塊的使用者,只需要通過(guò)模塊暴露的對(duì)象調(diào)用方法來(lái)實(shí)現(xiàn)對(duì)應(yīng)的功能。

具體請(qǐng)看下面的例子:

//index.html文件

//myModule.js文件
(function () {
  var msg = "Beijing"http://私有數(shù)據(jù)
  //操作數(shù)據(jù)的函數(shù)
  function doSomething() {
    console.log("doSomething() "+msg.toUpperCase())
  }
  function doOtherthing () {
    console.log("doOtherthing() "+msg.toLowerCase())
  }
  //向外暴露對(duì)象(給外部使用的兩個(gè)方法)
  window.myModule2 = {
    doSomething: doSomething,
    doOtherthing: doOtherthing
  }
})()

六、閉包的運(yùn)用

我們要實(shí)現(xiàn)這樣的一個(gè)需求: 點(diǎn)擊某個(gè)按鈕, 提示"點(diǎn)擊的是第n個(gè)按鈕",此處我們先不用事件代理:

.....



  

萬(wàn)萬(wàn)沒(méi)想到,點(diǎn)擊任意一個(gè)按鈕,后臺(tái)都是彈出“第四個(gè)”,這是因?yàn)閕是全局變量,執(zhí)行到點(diǎn)擊事件時(shí),此時(shí)i的值為3。那該如何修改,最簡(jiǎn)單的是用let聲明i

 for (let i = 0; i < btns.length; i++) {
      btns[i].onclick = function () {
        console.log("第" + (i + 1) + "個(gè)")
      }
    }

另外我們可以通過(guò)閉包的方式來(lái)修改:

   for (var i = 0; i < btns.length; i++) {
      (function (j) {
        btns[j].onclick = function (i) {
          console.log("第" + (i + 1) + "個(gè)")
        }
      })(i)
    }

如果覺(jué)得文章對(duì)你有些許幫助,歡迎在我的GitHub博客點(diǎn)贊和關(guān)注,感激不盡!

ps:文章于2018.11.16重新修改,希望對(duì)你們有所收獲!

參考文章

Javascript教程

你不知道的Javascript上卷

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

轉(zhuǎn)載請(qǐng)注明本文地址:http://www.ezyhdfw.cn/yun/98323.html

相關(guān)文章

  • JavaScript深入閉包

    摘要:深入系列第八篇,介紹理論上的閉包和實(shí)踐上的閉包,以及從作用域鏈的角度解析經(jīng)典的閉包題。定義對(duì)閉包的定義為閉包是指那些能夠訪問(wèn)自由變量的函數(shù)。 JavaScript深入系列第八篇,介紹理論上的閉包和實(shí)踐上的閉包,以及從作用域鏈的角度解析經(jīng)典的閉包題。 定義 MDN 對(duì)閉包的定義為: 閉包是指那些能夠訪問(wèn)自由變量的函數(shù)。 那什么是自由變量呢? 自由變量是指在函數(shù)中使用的,但既不是函數(shù)參數(shù)也...

    caige 評(píng)論0 收藏0
  • 【進(jìn)階2-2期】JavaScript深入之從作用域鏈理解閉包

    摘要:使用上一篇文章的例子來(lái)說(shuō)明下自由變量進(jìn)階期深入淺出圖解作用域鏈和閉包訪問(wèn)外部的今天是今天是其中既不是參數(shù),也不是局部變量,所以是自由變量。 (關(guān)注福利,關(guān)注本公眾號(hào)回復(fù)[資料]領(lǐng)取優(yōu)質(zhì)前端視頻,包括Vue、React、Node源碼和實(shí)戰(zhàn)、面試指導(dǎo)) 本周正式開(kāi)始前端進(jìn)階的第二期,本周的主題是作用域閉包,今天是第7天。 本計(jì)劃一共28期,每期重點(diǎn)攻克一個(gè)面試重難點(diǎn),如果你還不了解本進(jìn)階計(jì)...

    simpleapples 評(píng)論0 收藏0
  • 【進(jìn)階2-3期】JavaScript深入閉包面試題解

    摘要:閉包面試題解由于作用域鏈機(jī)制的影響,閉包只能取得內(nèi)部函數(shù)的最后一個(gè)值,這引起的一個(gè)副作用就是如果內(nèi)部函數(shù)在一個(gè)循環(huán)中,那么變量的值始終為最后一個(gè)值。 (關(guān)注福利,關(guān)注本公眾號(hào)回復(fù)[資料]領(lǐng)取優(yōu)質(zhì)前端視頻,包括Vue、React、Node源碼和實(shí)戰(zhàn)、面試指導(dǎo)) 本周正式開(kāi)始前端進(jìn)階的第二期,本周的主題是作用域閉包,今天是第8天。 本計(jì)劃一共28期,每期重點(diǎn)攻克一個(gè)面試重難點(diǎn),如果你還不了...

    alanoddsoff 評(píng)論0 收藏0
  • 深入淺出Javascript:面向?qū)ο笾?em>閉包

    摘要:理解閉包概念閉包是指有權(quán)訪問(wèn)另一個(gè)函數(shù)作用域中的變量的函數(shù)。閉包在執(zhí)行后,仍然可以訪問(wèn)內(nèi)部的,因?yàn)閷⒌膬?nèi)的活動(dòng)對(duì)象添加到了的作用域鏈。閉包的應(yīng)用監(jiān)聽(tīng)事件事件錯(cuò)誤的使用循環(huán)使用閉包封裝函數(shù),便于使用私有變量。 理解閉包 概念 閉包是指 有權(quán)訪問(wèn)另一個(gè)函數(shù)作用域中的變量的 函數(shù)。 函數(shù)式閉包(在內(nèi)部保存數(shù)據(jù)和對(duì)外部無(wú)副作用) 創(chuàng)建方法 在一個(gè)函數(shù)內(nèi)部創(chuàng)建另一個(gè)函數(shù)(閉包) 原理 普通函數(shù):...

    instein 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

tyheist

|高級(jí)講師

TA的文章

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