欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

JavaScript閉包中難點(diǎn)深入分析

 更新時(shí)間:2022年11月08日 16:03:03   作者:亦世凡華、  
閉包是js的一個(gè)難點(diǎn)也是它的一個(gè)特色,是我們必須掌握的js高級(jí)特性,下面這篇文章主要給大家介紹了關(guān)于JavaScript閉包函數(shù)的相關(guān)資料,需要的朋友可以參考下

初識(shí)閉包

閉包可謂是JS的一大難點(diǎn)也是面試中常見(jiàn)的問(wèn)題之一,今天開(kāi)始梳理一下閉包的知識(shí),請(qǐng)諸君品鑒。

什么是閉包

閉包是嵌套的內(nèi)部函數(shù);內(nèi)部函數(shù)包含被引用變量(函數(shù))的對(duì)象。閉包存在于嵌套的內(nèi)部函數(shù)中,例如在javascript中,只有函數(shù)內(nèi)部的子函數(shù)才能讀取局部變量,所以閉包可以理解成“定義在一個(gè)函數(shù)內(nèi)部的函數(shù)“。在本質(zhì)上,閉包是將函數(shù)內(nèi)部和函數(shù)外部連接起來(lái)。當(dāng)然如何直觀的查看閉包可以通過(guò)chrome來(lái)查看,這里有個(gè)坑需要反饋一下,新版的chrome需要先調(diào)用fun2()才允許debugger,這樣才能顯示閉包。

<script>
    function fn1(){
        var a = 2;
        function fn2(){//執(zhí)行函數(shù)定義就會(huì)產(chǎn)生閉包(不用調(diào)用內(nèi)部函數(shù))
            console.log(a);
        }
        //新版的chrome需要返回一下內(nèi)部函數(shù)才會(huì)顯示閉包
        return fn2()
    }
    fn1()
</script>

如何產(chǎn)生閉包

當(dāng)一個(gè)嵌套的內(nèi)部(子)函數(shù)引用了嵌套的外部(父)函數(shù)的變量(函數(shù))時(shí),就產(chǎn)生了閉包

<script>
    // 將函數(shù)作為另一個(gè)函數(shù)的返回值
    function fn1(){
        var a = 2;
        function fn2(){//
            a++;
            console.log(a);
        }
        return fn2 //將一個(gè)內(nèi)部函數(shù)作為一個(gè)外部函數(shù)的返回值返回
    }
    var f = fn1()
    //整個(gè)過(guò)程產(chǎn)生了一個(gè)閉包,主要看你產(chǎn)生了幾個(gè)內(nèi)部函數(shù)對(duì)象,調(diào)用了幾次外部函數(shù)
    //閉包的特點(diǎn)就是函數(shù)內(nèi)部的變量會(huì)一直存在于內(nèi)存中,不會(huì)立即釋放。
    f()//3   這里的f()是調(diào)用了內(nèi)部函數(shù)
    f()//4
</script>

<script>
    // 將函數(shù)作為實(shí)參傳遞給另一個(gè)函數(shù)調(diào)用
    function showDelay(msg,time){
        //setTimeout 的第一個(gè)參數(shù)是函數(shù),符合閉包的規(guī)則
        setTimeout(function(){
            alert(msg)
        },time)
    }
    showDelay('張三',2000)
</script>

產(chǎn)生閉包條件

函數(shù)嵌套;內(nèi)部函數(shù)引用了外部函數(shù)的數(shù)據(jù)(變量/函數(shù))。

閉包的作用

使用函數(shù)內(nèi)部的變量在函數(shù)執(zhí)行完畢后,仍然存活在內(nèi)存中(延長(zhǎng)了局部變量的生命周期);讓函數(shù)外部可以操作(讀寫(xiě))到函數(shù)內(nèi)部的數(shù)據(jù)(變量/函數(shù))。

閉包的生命周期

產(chǎn)生:在嵌套的內(nèi)部函數(shù)定義執(zhí)行完時(shí)就產(chǎn)生了(不是在調(diào)用),死亡:在嵌套的內(nèi)部函數(shù)稱(chēng)為垃圾對(duì)象時(shí)就死亡了。

<script>
    function fn1 () {
        //此時(shí)閉包就已經(jīng)產(chǎn)生了(函數(shù)提升,內(nèi)部函數(shù)對(duì)象已經(jīng)創(chuàng)建了)
        var a = 2;
        function fn2 () {//
            a++;
            console.log(a);
        }
        return fn2 //將一個(gè)內(nèi)部函數(shù)作為一個(gè)外部函數(shù)的返回值返回
    }
    var f = fn1()
    f()//3   
    f()//4
    f = null //閉包死亡(包含閉包的函數(shù)對(duì)象成為垃圾對(duì)象)
</script>

閉包的應(yīng)用

定義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)的功能。

//myModule.js 文件
function myModule(){
    // 私有數(shù)據(jù)
    var msg = 'My Module'
    function showUpper(){
        console.log('showUpper' +msg.toUpperCase());
    }
    function showLow(){
        console.log('showLow' +msg.toLowerCase());
    }
    //向外暴露對(duì)象(給外部使用的方法)
    return {
        showUpper:showUpper,
        showLow:showLow
    }
}
//index.html文件
<script src="./myModule.js"></script>
<script>
    var module = myModule()
    module.showUpper()
    module.showLow()
</script>
 

我們也可以通過(guò)匿名函數(shù)來(lái)實(shí)現(xiàn)閉包,這樣能很便捷的調(diào)用閉包里面的屬性,雖然會(huì)達(dá)到我們想要的效果,但是可能會(huì)造成全局的變量名污染,建議使用第一種。

//myModule2.js文件
(function(){
    // 私有數(shù)據(jù)
    var msg = 'My Module'
    // 操作數(shù)據(jù)的函數(shù)
    function showUpper(){
        console.log('showUpper' +msg.toUpperCase());
    }
    function showLow(){
        console.log('showLow' +msg.toLowerCase());
    }
    //向外暴露對(duì)象(給外部使用的方法)
    window.myModule2 = {
        showUpper:showUpper,
        showLow:showLow
    }
})()
//index.js文件
<script src="./myModule2.js"></script>
<script>
    myModule2.showUpper()
    myModule2.showLow()
</script

閉包的缺點(diǎn)及解決方法

在我們使用閉包過(guò)程中,函數(shù)執(zhí)行完后,函數(shù)內(nèi)部的局部變量沒(méi)有釋放,占用內(nèi)存時(shí)間會(huì)變長(zhǎng),容易造成內(nèi)存泄漏,所以在日常開(kāi)發(fā)中,盡量避免閉包的出現(xiàn),或者要對(duì)局部變量及時(shí)釋放。

<script>
    function fn1(){
        var arr = new Array[100000]
        function fn2(){
            console.log(arr.length);
        }
        return fn2
    }
    var f = fn1()
    f()
    //不用閉包或者回收閉包
    f = null//讓內(nèi)部函數(shù)成為垃圾對(duì)象 --> 回收閉包
</script>

內(nèi)存溢出:一種程序運(yùn)行出現(xiàn)的錯(cuò)誤,當(dāng)程序運(yùn)行需要的內(nèi)存超過(guò)了剩余的內(nèi)存時(shí),就會(huì)拋出內(nèi)存溢出的錯(cuò)誤。

<script>
    var obj = {}
    for(var i=0;i<10000;i++){
        obj[i]=new Array(1000000)
        console.log('------');
    }
</script>

內(nèi)存泄漏:占用的內(nèi)存沒(méi)有及時(shí)釋放,內(nèi)存泄漏積累多了就容易導(dǎo)致內(nèi)存溢出。常見(jiàn)的內(nèi)存泄漏:意外的全局變量、沒(méi)有及時(shí)清理的計(jì)時(shí)器或回調(diào)函數(shù)、閉包。

<script>
    //意外的全局變量
    function fn(){
        a = 10;
        console.log(a);
    }
    // 調(diào)用函數(shù)雖然能打印a,但是a并沒(méi)有被釋放掉。一不注意就設(shè)置了一個(gè)全局變量
    fn()
    //沒(méi)有及時(shí)清理計(jì)時(shí)器或回調(diào)函數(shù)
    var intervalId = setInterval(function(){ //啟動(dòng)循環(huán)定時(shí)器后不清理
        console.log('--------');
    },2000)
    // clearInterval(intervalId)
    //閉包
    function fn1(){
        var a = 2 //閉包 a 并沒(méi)有被釋放掉
        function fn2(){
            console.log(++a)
        }
        return fn2
    }
    var f = fn1()
    f()
    // f = null 不執(zhí)行這條語(yǔ)句,a的值一直在
</script>

閉包案例

<script>
    // 案例一:
    var name = "this is Window"
    var object = {
        name:"this is Object",
        getName:function(){
            return function(){
                return this.name
            }
        }
    }
    //閉包的this只能是全局,若在當(dāng)前作用域中定義了this,就直接使用定義的this,若沒(méi)定義,則需要一層層向外找,直到全局為止
    //本題是沒(méi)有閉包的
    alert(object.getName()())//this is Window
    // 案例二:
    var name1 = "this is Window"
    var object1 = {
        name1:"this is Object",
        getName:function(){
            //定義的that形成了閉包,內(nèi)部函數(shù)引用了外部函數(shù)的變量,而this指向的是object,所以返回的是object中的name1
            var that = this;
            return function(){
                return that.name1
            }
        }
    }
    alert(object1.getName()())// this is Object
</script>
<script>
    //沒(méi)有使用閉包的話,數(shù)據(jù)是沒(méi)有保留的,所以n傳遞給o之后,下次運(yùn)算o值還是上次的值不會(huì)發(fā)生改變
    function fun(n,o){
        console.log(o);
        return{
            fun:function(m){
                return fun(m,n)
            }
        }
    }
    //在執(zhí)行fun(0)之后,n被之前的n=0,一直被調(diào)用
    var a = fun(0); //閉包里面的n傳入了0
    a.fun(1); 
    a.fun(2);
    a.fun(3)//undefined,0,0,0
    //鏈?zhǔn)綀?zhí)行會(huì)導(dǎo)致n的改變,n是前面函數(shù)執(zhí)行的形參
    var b = fun(0).fun(1).fun(2).fun(3)//undefined,0,1,2
    //c.fun(2)、c.fun(3)都調(diào)用了fun(1)留下的閉包n
    var c = fun(0).fun(1); 
    c.fun(2); 
    c.fun(3)//undefined,0,1,1
</script>

到此這篇關(guān)于JavaScript閉包中難點(diǎn)深入分析的文章就介紹到這了,更多相關(guān)JS閉包內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • three.js簡(jiǎn)單實(shí)現(xiàn)類(lèi)似七圣召喚的擲骰子

    three.js簡(jiǎn)單實(shí)現(xiàn)類(lèi)似七圣召喚的擲骰子

    這篇文章主要為大家介紹了three.js簡(jiǎn)單實(shí)現(xiàn)類(lèi)似七圣召喚的擲骰子示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-01-01
  • 深入了解Javascript的事件循環(huán)機(jī)制

    深入了解Javascript的事件循環(huán)機(jī)制

    單線程的同步等待極大影響效率,任務(wù)不得不一個(gè)一個(gè)等待執(zhí)行,對(duì)于網(wǎng)頁(yè)應(yīng)用是無(wú)法接受的。所以Javascript使用事件循環(huán)機(jī)制來(lái)解決異步任務(wù)的問(wèn)題。本文就來(lái)講講Javascript的事件循環(huán)機(jī)制,希望對(duì)你有所幫助
    2022-09-09
  • 微信小程序日歷彈窗選擇器代碼實(shí)例

    微信小程序日歷彈窗選擇器代碼實(shí)例

    這篇文章主要介紹了微信小程序日歷彈窗選擇器,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-05-05
  • JS字典Dictionary類(lèi)定義與用法示例

    JS字典Dictionary類(lèi)定義與用法示例

    這篇文章主要介紹了JS字典Dictionary類(lèi)定義與用法,結(jié)合實(shí)例形式分析了javascript字典Dictionary的定義、添加、移除、統(tǒng)計(jì)等相關(guān)操作技巧,需要的朋友可以參考下
    2019-02-02
  • 小程序多圖列表實(shí)現(xiàn)性能優(yōu)化的方法步驟

    小程序多圖列表實(shí)現(xiàn)性能優(yōu)化的方法步驟

    這篇文章主要介紹了小程序多圖列表實(shí)現(xiàn)性能優(yōu)化的方法步驟,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-05-05
  • JS實(shí)現(xiàn)數(shù)組淺拷貝和深拷貝的方法

    JS實(shí)現(xiàn)數(shù)組淺拷貝和深拷貝的方法

    淺拷貝創(chuàng)建一個(gè)新的對(duì)象,來(lái)接受重新復(fù)制或引用的對(duì)象值,如果對(duì)象屬性是基本的數(shù)據(jù)類(lèi)型,復(fù)制的就是基本類(lèi)型的值給新對(duì)象,這篇文章主要介紹了js實(shí)現(xiàn)數(shù)組淺拷貝和深拷貝,需要的朋友可以參考下
    2024-01-01
  • 正則表達(dá)式判斷是否存在中文和全角字符和判斷包含中文字符串長(zhǎng)度

    正則表達(dá)式判斷是否存在中文和全角字符和判斷包含中文字符串長(zhǎng)度

    對(duì)于一些更安全的容錯(cuò)嚴(yán)重,需要用到
    2008-09-09
  • Javascript操作select控件代碼實(shí)例

    Javascript操作select控件代碼實(shí)例

    這篇文章主要介紹了Javascript操作select控件代碼實(shí)例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-02-02
  • 一文熟練掌握J(rèn)avaScript的switch用法

    一文熟練掌握J(rèn)avaScript的switch用法

    在JavaScript中switch語(yǔ)句是一種用于多條件分支的控制語(yǔ)句,下面這篇文章主要給大家介紹了關(guān)于如果通過(guò)一文熟練掌握J(rèn)avaScript的switch用法的相關(guān)資料,文中通過(guò)代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2024-01-01
  • 詳解單頁(yè)面路由工程使用微信分享及二次分享解決方案

    詳解單頁(yè)面路由工程使用微信分享及二次分享解決方案

    這篇文章主要介紹了詳解單頁(yè)面路由工程使用微信分享及二次分享解決方案,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2019-02-02

最新評(píng)論