国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

深入理解JavaScript(二):由一道題來思考閉包

曹金海 / 1275人閱讀

摘要:中所有的事件綁定都是異步編程當前這件事件沒有徹底完成,不再等待,繼續執行下面的任務當綁定事件后,不需要等待執行,繼續執行下一個循環任務,所以當我們點擊執行方法的時候,循環早已結束即是最后。

概念
閉包就是指有權訪問另一個函數作用域中的變量的函數
    
    
    
    
    點擊li標簽彈出對應數字
    
    
    
  • 0
  • 1
  • 2
  • 3

如上題,最為常見的一個例子,這里解釋由這道題引出的js知識點,如上我們知道在瀏覽器運行無論點擊哪個li標簽都是彈出3,首先來理解為什么會彈出3。

程序通過for循環給每個li標簽綁定了事件,然后通過點擊li標簽觸發方法,即執行alert(i)。js中有個作用域鏈查找機制,首先會在onclick返回的函數作用域查找i變量的值,找不到則往上一層找i,上一層即是window全局作用域,即找到全局變量i,即for循環定義的i。

注意for循環的i并不是私有變量,而是全局變量。

js中所有的事件綁定都是異步編程(當前這件事件沒有徹底完成,不再等待,繼續執行下面的任務)

當綁定onclick事件后,不需要等待執行,繼續執行下一個循環任務,所以當我們點擊執行方法的時候,循環早已結束,即是最后i=3。故程序執行后全局變量i被循環執行后賦值為最終的3,所以當點擊的時候,外層循環已經結束,頁面加載完成預示著js代碼都已經執行完成,即執行alert(i)時,由于i不是私有變量,便會找到上一級window作用域全局的i,所以無論點擊哪個li標簽都是彈出3

為什么要用閉包

那么,解決這個問題的緣由,在于i每次在頁面加載完就賦值為3,alert(i)的時候總是找到全局變量i。在ES5傳統語法中,能形成作用域的只有全局和函數,現在每次i找的都是全局,那么要保住i的值只能在全局和onclick返回函數的作用域中間再加一個小的私有作用域,即是大的作用域外再加一個小的作用域,這樣i往上一層作用域查找時,就會獲取小作用域的i的值,而不會去獲取全局變量的i值。

這個思路解決問題就需要引入閉包,在這個理解上閉包是指函數變量可以保存在函數作用域內,因此看起來是函數將變量“包裹”了起來。于是,代碼改成:

for(var i = 0;i < list.length;i++){
    list[i].onclick = (function(n){//形參n
        //=>讓自執行函數執行,把執行的返回值(return)賦值給onclick
        //(此處onclick綁定的是返回的小函數,點擊的時候執行的是小函數),
        // 自執行函數在給事件賦值的時候就已經執行了
        // 自執行函數形成一個私有作用域
        var i = n;
        return function(){
            alert(i);
        }
    })(i);//傳入實參i
}

循環三次,形成三個不銷毀的私有作用域(自執行函數執行),而每一個不銷毀的棧內存中都存儲了一個私有變量i,而這個值分別是每一次執行傳遞進來的全局i的值(也就是:第一個不銷毀的作用域存儲的是0,第二個是1,第三個是2,第四個是3);當點擊的時候,執行返回的小函數,遇到變量i,向它自己的上級作用域查找。這樣就達到了我們需要的效果,這種閉包實現,也可以有另一種寫法。

/*原理同法二都是形成三個不銷毀的私有作用域,分別存儲需要的索引值*/
for(var i = 0;i < list.length;i++){
    (function(n){
        list[n].onclick = function(){
            alert(n);
        } 
    })(i)
}

對于初始的代碼,如果說為什么不能實現,那原因就可歸納為:

1.執行方法,形成一個私有的棧內存,遇到變量i,i不是私有變量,向上一級作用域查找(上級作用域window)
2.所有的事件綁定都是異步編程,綁定事件后,不需要等待執行,繼續執行下一個循環任務,所以當我們點擊執行方法的時候,循環早已結束(讓全局的i等于循環最后的結果3)
ES6語法的解決方式

在ES6中,解決這種問題只需要一個let變量,ES6中才有塊級作用域(類似于私有作用域)的概念

for(let i = 0;i < list.length;i++){
    list[i].onclick = function(){
        alert(i);
    }
}
閉包對內存的影響

從上面可知,每次for都會形成一個私有作用域,每個都里面保存的變量i的值,程序運行后這些作用域并不會被銷毀,所以由于閉包會攜帶包含它的函數的作用域,所以會比其他函數占用更多內容,過度使用閉包會導致內存占用過多。

在真實項目中為了保證JS的性能(堆棧內存的性能優化),應該盡可能的減少閉包的使用(不銷毀的堆棧內存是耗性能的)

堆內存和棧內存的釋放

這里又要提到一個知識點,js中存儲方式的分類:

JS中的內存分為堆內存和棧內存
堆內存:存儲引用數據類型值(對象:鍵值對 函數:代碼字符串)
棧內存:提供JS代碼執行的環境和存儲基本類型值

粗暴理解var定義的變量存在棧內存中,如for循環中的i是存在棧內存中的;而函數,它是存在堆內存中

一般情況下,當函數執行完成,所形成的私有作用域(棧內存)都會自動釋放掉(在棧內存中存儲的值也都會釋放掉),那為什么閉包的棧內存不會被自動釋放掉,在js中也有特殊不被銷毀的情況:

1.函數執行完成,當前形成的棧內存中,某些內容被棧內存以外的變量占用了,此時棧內存不能釋放(一旦釋放外面找不到原有的內容了)
2.全局棧內存只有在頁面關閉的時候才會被釋放掉

閉包則是屬于第一種情況,onclick函數形成的棧內存,被小函數【alert(i),i找到onclick作用域獲取i值】占用了onclick函數的棧內存(變量i是存在棧內存中),故棧內存不能被釋放,所以才會說閉包過度使用容易導致內存被占用過多,因為不會自動釋放內存。

堆內存的釋放

堆內存讓所有引用堆內存空間地址的變量賦值為null即可(沒有變量占用這個堆內存了,瀏覽器會在空閑的時候把它釋放掉)

文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。

轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/106351.html

相關文章

  • 【進階1-4期】JavaScript深入之帶你走進內存機制

    摘要:引擎對堆內存中的對象進行分代管理新生代存活周期較短的對象,如臨時變量字符串等。內存泄漏對于持續運行的服務進程,必須及時釋放不再用到的內存。 (關注福利,關注本公眾號回復[資料]領取優質前端視頻,包括Vue、React、Node源碼和實戰、面試指導) 本周正式開始前端進階的第一期,本周的主題是調用堆棧,今天是第4天。 本計劃一共28期,每期重點攻克一個面試重難點,如果你還不了解本進階計劃...

    不知名網友 評論0 收藏0
  • JavaScript深入之執行上下文

    摘要:深入系列第七篇,結合之前所講的四篇文章,以權威指南的為例,具體講解當函數執行的時候,執行上下文棧變量對象作用域鏈是如何變化的。前言在深入之執行上下文棧中講到,當代碼執行一段可執行代碼時,會創建對應的執行上下文。 JavaScript深入系列第七篇,結合之前所講的四篇文章,以權威指南的demo為例,具體講解當函數執行的時候,執行上下文棧、變量對象、作用域鏈是如何變化的。 前言 在《Jav...

    gougoujiang 評論0 收藏0
  • web前端面試題一

    摘要:需求一個輸入框,用戶輸入時有聯想搜索,每次用戶輸入都會觸發請求,過多的請求會造成服務器的壓力,如何去解決這個問題請求函數面試者延遲發送可以去解決這樣的問題。 寫在前面的話 一般來說,面試質量的高低很大程度影響公司是否想接受改人才,也影響了人才是否愿意去公司。質量高的面試,公司能表明對人才的要求,個人也能表明所期待的公司是一個什么模式的公司。最終會有利于雙向選擇的過程。能盡早的把問題暴露...

    bergwhite 評論0 收藏0
  • 程序語言

    摘要:一面應該還問了其他內容,但是兩次面試多線程面試問題和答案采訪中,我們通常會遇到兩個主題采集問題和多線程面試問題。多線程是關于并發和線程的。我們正在共享重要的多線程面試問題和答案。。 2016 年末,騰訊,百度,華為,搜狗和滴滴面試題匯總 2016 年未,騰訊,百度,華為,搜狗和滴滴面試題匯總 【碼農每日一題】Java 內部類(Part 2)相關面試題 關注一下嘛,又不讓你背鍋!問:Ja...

    mtunique 評論0 收藏0
  • 程序語言

    摘要:一面應該還問了其他內容,但是兩次面試多線程面試問題和答案采訪中,我們通常會遇到兩個主題采集問題和多線程面試問題。多線程是關于并發和線程的。我們正在共享重要的多線程面試問題和答案。。 2016 年末,騰訊,百度,華為,搜狗和滴滴面試題匯總 2016 年未,騰訊,百度,華為,搜狗和滴滴面試題匯總 【碼農每日一題】Java 內部類(Part 2)相關面試題 關注一下嘛,又不讓你背鍋!問:Ja...

    stefan 評論0 收藏0

發表評論

0條評論

最新活動
閱讀需要支付1元查看
<