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

資訊專(zhuān)欄INFORMATION COLUMN

一篇文章帶你理解閉包

bluesky / 1552人閱讀

摘要:通過(guò)例子再來(lái)回顧一下閉包的理解所謂的閉包就是可以創(chuàng)建一個(gè)獨(dú)立的環(huán)境,每個(gè)閉包里面的環(huán)境都是獨(dú)立的,互不干擾。此時(shí)就是一個(gè)閉包,這樣寫(xiě)有些麻煩,我們對(duì)此改進(jìn)一下。參考文章初識(shí)中的閉包從閉

走在前端的大道上

本篇將自己讀過(guò)的相關(guān) javascript閉包 文章中,對(duì)自己有啟發(fā)的章節(jié)片段總結(jié)在這(會(huì)對(duì)原文進(jìn)行刪改),會(huì)不斷豐富提煉總結(jié)更新。

首先著重回顧一下 全局變量 和 局部變量 全局變量:可以在任意位置訪問(wèn)的量就叫 全局變量

 

var age = 20;
 function a(){
     console.log(age); //20
}
a();
局部變量:函數(shù)中用var定義的變量,只能在函數(shù)中訪問(wèn)這個(gè)變量,函數(shù)外部訪問(wèn)不了。
function a(){
    var age = 20;
}
a();
console.log(age); // Uncaught ReferenceError: age is not defined

重點(diǎn):

1.在函數(shù)中如果不使用var定義變量那么js引擎會(huì)自動(dòng)添加成全局變量。
2.全局變量從創(chuàng)建的那一刻起就會(huì)一直保存在內(nèi)存中,除非你關(guān)閉這個(gè)頁(yè)面,局部變量當(dāng)函數(shù)運(yùn)行完以后就會(huì)銷(xiāo)毀這個(gè)變量,假如有多次調(diào)用這個(gè)函數(shù)它下一次調(diào)用的時(shí)候又會(huì)重新創(chuàng)建那個(gè)變量,既運(yùn)行完就銷(xiāo)毀,回到最初的狀態(tài),簡(jiǎn)單來(lái)說(shuō)局部變量是一次性的,用完就扔,下次要我再重新創(chuàng)建。
函數(shù)的相關(guān)知識(shí)點(diǎn):

1.一個(gè)函數(shù)內(nèi)可以嵌套多個(gè)函數(shù)
2.函數(shù)里面的子函數(shù)可以訪問(wèn)它上級(jí)定義的變量,注意不只是一級(jí),如果上級(jí)沒(méi)有會(huì)繼續(xù)往上級(jí)找,直到找到為止,如果找到全局變量到找不到就會(huì)報(bào)錯(cuò)。

function a(){
 var name = "追夢(mèng)子";
 function b(){
     console.log(name); // "追夢(mèng)子"
 }
 b();
}
a();

3.函數(shù)的另外一種調(diào)用形式,你可以把它叫做自調(diào)用,自己調(diào)用自己,達(dá)到自執(zhí)行的效果。

var a = 0;
(function(){
   console.log(++a); // 1
})()

這種方式用()把內(nèi)容包裹起來(lái),后面的()表示執(zhí)行這個(gè)函數(shù),可能你會(huì)問(wèn)為什么要把函數(shù)包起來(lái),如果不包裹起來(lái),js會(huì)把它當(dāng)作函數(shù)聲明來(lái)處理,如果包裹起來(lái)就是表達(dá)式。

正題
閉包說(shuō)得通熟易懂一點(diǎn),就是指 有權(quán)訪問(wèn)另一個(gè)函數(shù)作用域變量的函數(shù)。閉包可以解決函數(shù)外部無(wú)法訪問(wèn)函數(shù)內(nèi)部變量的問(wèn)題。創(chuàng)建閉包的常見(jiàn)方式,就是在一個(gè)函數(shù)內(nèi)部創(chuàng)建另外一個(gè)函數(shù),并返回。

下面是一段沒(méi)有使用閉包的代碼:

function fn(){
 var a = 10; //報(bào)錯(cuò)
}
alert(a);

因?yàn)閍沒(méi)有定義,雖然函數(shù)fn里面定義了a但是,但是它只能在函數(shù)fn中使用。也就是作用域的問(wèn)題。

function fn(){
  //定義了一個(gè)變量name
 var name = "追夢(mèng)子";
  //外部想訪問(wèn)這個(gè)變量name怎么辦?return!把它返回出去,再用個(gè)變量接收一下不就可以了
  return name;
}
var name = fn();//接收f(shuō)n返回的name值。
alert(name);//追夢(mèng)子;

這里的閉包就是利用函數(shù)的return。除了通過(guò)return還可以通過(guò)其他的幾種方法如下:
方法1:

function fn(){
  var a = 0;
  b = a;
}
alert(b)

 這里利用了js的一個(gè)特性,如果在函數(shù)中沒(méi)有用var定義變量,那么這個(gè)變量屬于全局的,但這種方法多少有些不好。

方法2:

var f = null;
function fn(){
  var a = 0;
  f = function(){
    a++;
    f.a = a;
  };
}
fn();
f();
alert(f.a);//1
f();
alert(f.a);//2

其實(shí)閉包還有一個(gè)很重要的特性,來(lái)看一個(gè)例子。

var lis= document.getElementsByTagName["li"]; 
 //假如這段代碼中的lis.length = 5;
for(var i=0;i

最終結(jié)果是不管單擊哪個(gè)li元素都是彈5。不信你試試。為什么呢??聪旅娣治觥?/p>

for(var i=0;i

為什么會(huì)這樣呢,因?yàn)槟鉬or循環(huán)只是給li綁定事件,但是里面的函數(shù)代碼并不會(huì)執(zhí)行啊,這個(gè)執(zhí)行是在你點(diǎn)擊的時(shí)候才執(zhí)行的好吧?但是此時(shí)的i已經(jīng)是5了,所以所有的都打印出5來(lái)了。

for(var i=0;i

閉包的特點(diǎn)不只是讓函數(shù)外部訪問(wèn)函數(shù)內(nèi)部變量這么簡(jiǎn)單,還有一個(gè)大的特點(diǎn)就是 通過(guò)閉包可以讓函數(shù)中的變量持久保持。

function fn(){
   var num = 5;
   num+=1;
   alert(num);
}  
 fn(); //6
 fn(); //6

為什么都是 6 呢?因?yàn)?函數(shù)一旦調(diào)用里面的內(nèi)容就會(huì)被銷(xiāo)毀,下一次調(diào)用又是一個(gè)新的函數(shù),和上一個(gè)調(diào)用的不相關(guān)了。

劃重點(diǎn):JavaScript中有回收機(jī)制,函數(shù)沒(méi)有被引用 且執(zhí)行完以后這個(gè)函數(shù)的作用域就會(huì)被銷(xiāo)毀,如果一個(gè)函數(shù)被其他變量引用,這個(gè)函數(shù)的作用域?qū)⒉粫?huì)被銷(xiāo)毀,(簡(jiǎn)單來(lái)說(shuō)就是函數(shù)里面的變量會(huì)被保存下來(lái),你可以理解成全局變量。)

再來(lái)

function fn(){
 var num = 0;
 return function(){
   num+=1;
     alert(num);   
   };  
}
var f = fn();
f(); //1
f(); //2

定義了一個(gè)fn函數(shù),里面有個(gè)num默認(rèn)為0,接著返回了一個(gè)匿名函數(shù)(也就是沒(méi)有名字的函數(shù))。我們?cè)谕獠坑?f 接收這個(gè)返回的函數(shù)。這個(gè)匿名函數(shù)干的事情就是把 num 加 1,還有我們用來(lái)調(diào)試的 alert 。

這里之所以執(zhí)行完這個(gè)函數(shù) num 沒(méi)有被銷(xiāo)毀,是因?yàn)槟莻€(gè)匿名函數(shù)的問(wèn)題,因?yàn)檫@個(gè)匿名函數(shù)用到了這個(gè) num,所以沒(méi)有被銷(xiāo)毀,一直保持在內(nèi)存中,因此我們 f() 時(shí) num 可以一直加。

function a(){
    var aa = 0;
    function b(){
        aa ++;
        console.log(aa);
    }
    return b;
}
var ab = a();
ab(); //1
ab(); //2

里面的變量的值沒(méi)有被銷(xiāo)毀,因?yàn)楹瘮?shù)a被外部的變量ab引用,所以變量aa沒(méi)有被回收。

如果某個(gè)函數(shù)被它的父函數(shù)之外的一個(gè)變量引用,就形成了一個(gè)閉包

還有一種更為常用的閉包寫(xiě)法

var bi = (function(){
    var a = 0;
    function b(){
        a ++;
        console.log(a);
    }
    return b;
})();

bi(); //1
bi(); //2
bi(); //3

執(zhí)行過(guò)程分析:

  首先把一個(gè)自執(zhí)行函數(shù)賦值給了bi,這個(gè)自執(zhí)行函數(shù)運(yùn)行完成以后就bi的值就變成了

function b(){
    a ++;
    console.log(a);
}

  因?yàn)槲覀冊(cè)谏厦娴拇a return 回去了 b,然后因?yàn)檫@個(gè)自執(zhí)行函數(shù)被 bi 引用所以里面的變量 a 并沒(méi)有因?yàn)檫@個(gè)自執(zhí)行函數(shù)執(zhí)完而銷(xiāo)毀,而是保存到了內(nèi)存中,所以我們多次打印 bi()
就成了1、2、3

閉包是使用可以帶來(lái)以下好處:

希望一個(gè)變量長(zhǎng)期駐扎在內(nèi)存中

避免全局變量的污染

私有成員的存在

閉包可以讀取到函數(shù)內(nèi)部的變量,這是由于閉包后函數(shù)的堆棧不會(huì)釋放,也就是說(shuō)這些值始終保持在內(nèi)存中。這是一個(gè)優(yōu)點(diǎn),也是一個(gè)缺點(diǎn)。

通過(guò)例子再來(lái)回顧一下

閉包的理解:
  所謂的閉包就是可以創(chuàng)建一個(gè)獨(dú)立的環(huán)境,每個(gè)閉包里面的環(huán)境都是獨(dú)立的,互不干擾。
閉包的創(chuàng)建:
  一個(gè)函數(shù)中嵌套另外一個(gè)函數(shù),并且將這個(gè)函數(shù)return出去,然后將這個(gè)return出來(lái)的函數(shù)保存到了一個(gè)變量中,那么就創(chuàng)建了一個(gè)閉包。
var arr = [];
for(var i=0;i<2;i++){
    arr[i] = function(){
        console.log(i);
    }
}
arr[0](); //2
arr[1](); //2

  實(shí)際情況我們是要打印0,1,2,3這樣的數(shù),但是每次都是打印2,什么情況呢?雖然我們?cè)趂or中給arr的每個(gè)值添加了一個(gè)匿名函數(shù),但是 在for循環(huán)中我們并沒(méi)有執(zhí)行這個(gè)函數(shù),而是在for循環(huán)以后執(zhí)行的這個(gè)函數(shù),那么自然打印出來(lái)的就是for循環(huán)完以后i的值。

var arr = [];
// for(var i=0;i<2;i++){
    var i = 2;
    arr[0] = function(){
        console.log(i);
    }
    arr[1] = function(){
        console.log(i);
    }
// }
arr[0](); //2
arr[1](); //2

  相當(dāng)于這樣,雖然這個(gè)函數(shù)沒(méi)有執(zhí)行,但是arr的i已經(jīng)給執(zhí)行了,因?yàn)閍rr不是函數(shù)啊,肯定是執(zhí)行的,而你函數(shù)沒(méi)有調(diào)用自然就不會(huì)執(zhí)行,當(dāng)函數(shù)調(diào)用的時(shí)候i已經(jīng)是2了。既然如此只要我們?cè)趂or循環(huán)的時(shí)候直接執(zhí)行這個(gè)函數(shù)就ok。

var arr = [];
for(var i=0;i<2;i++){
    arr[i] = function(){
        console.log(i);
    }
    arr[i]();
}
//0
//1

 這樣,在每一次for循環(huán)的時(shí)候就直接執(zhí)行了這個(gè)函數(shù),打印正常,但是我們這樣同樣有一個(gè)問(wèn)題,那就是在每一次for循環(huán)的時(shí)候這個(gè)函數(shù)就已經(jīng)被執(zhí)行了,我們要的是我們想什么時(shí)候調(diào)用就時(shí)候調(diào)用,而不是直接在for執(zhí)行中直接執(zhí)行,那么顯然這樣做是達(dá)不到我們的目的的。

  現(xiàn)在我們?cè)谙胂腴]包的概念,閉包可以創(chuàng)建獨(dú)立的環(huán)境,并且每一個(gè)閉包的環(huán)境是獨(dú)立的,也就是說(shuō),我們可以通過(guò)閉包來(lái)保存這些不同的變量。

我們回顧一下閉包的創(chuàng)建方法:一個(gè)函數(shù)中嵌套另外一個(gè)函數(shù),并且將這個(gè)函數(shù)return出去,然后將這個(gè)return出來(lái)的函數(shù)保存到了一個(gè)變量中,那么就創(chuàng)建了一個(gè)閉包。

var arr = [];
for(var i=0;i<2;i++){
    arr[i] = a(i);
}

function a(i){
    return function(){
        console.log(i);
    }
}

arr[0](); //0
arr[1](); //1

   此時(shí)就是一個(gè)閉包,這樣寫(xiě)有些麻煩,我們對(duì)此改進(jìn)一下。

var arr = [];
for(var i=0;i<3;i++){
    arr[i] = (function(i){
        return function(){
            console.log(i);
        }
    })(i)
}

arr[0](); //0
arr[1](); //1
arr[2](); //2

還可以這樣

var arr = [];
for(var i=0;i<3;i++){
    (function(i){
        arr[i] = function(){
            console.log(i);
        }
    })(i)
}

arr[0](); //0
arr[1](); //1
arr[2](); //2

 此時(shí) arr 里面的 i 用的是閉包里面的 i,而不是 for 中的 i,因?yàn)槲覀冋f(shuō)過(guò)每個(gè)閉包的環(huán)境都是獨(dú)立的。

js中的回收機(jī)制
function a(){
  var num = 10;
  return function(){
    num ++;
    console.log(num);
  }
}
a()(); //11
a()(); //11

按理說(shuō)第二次執(zhí)行函數(shù)a的時(shí)候應(yīng)該打印出12才對(duì),但是打印的卻是11。

首先來(lái)看看我們的理解

1.我們?cè)诤瘮?shù)a中返回了一個(gè)匿名函數(shù),在這個(gè)匿名函數(shù)中我們num++了一下,然后我們?cè)诤瘮?shù)外面執(zhí)行了這個(gè)匿名函數(shù)函數(shù),(第一括號(hào)執(zhí)行函數(shù)a第二個(gè)括號(hào)執(zhí)行這個(gè)rutrun回去的函數(shù))
2.現(xiàn)在num是11,然后我們又執(zhí)行了一次這個(gè)函數(shù),你們應(yīng)該是12吧,為什么不是呢?

實(shí)際js的執(zhí)行

  但是js的設(shè)計(jì)者為了讓沒(méi)有必要的變量保存在內(nèi)存中,(我們寫(xiě)的任何變量都是需要內(nèi)存空間的),什么叫沒(méi)有必要的變量?也就是說(shuō)你不在需要這個(gè)變量的時(shí)候它就會(huì)被銷(xiāo)毀?那么你肯定會(huì)問(wèn)js怎么知道那些變量是我們不需要的哪些是我們需要的。所以js為了知道哪些變量需要保存下來(lái),哪些不需要保存下來(lái),會(huì)進(jìn)行一些判斷。接下來(lái)我們就一起看看js是怎么判斷的。

1.在js中定義的全局變量是不會(huì)被銷(xiāo)毀的,因?yàn)槲覀冸S時(shí)都可能會(huì)用到這個(gè)變量,所以不能被銷(xiāo)毀。

2.但是在函數(shù)中定義的變量就不一定了,而且由于在函數(shù)的定義的變量的生命周期在執(zhí)行完這個(gè)函數(shù)就銷(xiāo)毀的原因自然就保存不了上一次的值。

3.但是并不是說(shuō)函數(shù)就真的保存不了上一次的值,因?yàn)橛械臅r(shí)候我們確實(shí)需要上一次的值,所以js判斷是否需要保存上一次變量的值的時(shí)候就會(huì)遵守這樣一個(gè)規(guī)則:

如果這個(gè)函數(shù)有被外部的變量引用就不會(huì)銷(xiāo)毀(這句話說(shuō)的不夠準(zhǔn)確,下面代碼會(huì)一步一步解釋?zhuān)?,否則銷(xiāo)毀。怎么理解這句話呢?

function a(){
    var b = 0;
    return function(){
        b ++;
        console.log(b);
    }
}

var d = a();
d();//1
d();//2

  函數(shù)a被變量d引用,更準(zhǔn)確的說(shuō)是函數(shù)a里面的那個(gè)匿名函數(shù)被變量d所引用,因?yàn)樽兞縟等于的是函數(shù)a執(zhí)行完成后的值,而函數(shù)a執(zhí)行完以后又因?yàn)楹瘮?shù)a返回了那個(gè)匿名函數(shù),所以準(zhǔn)確的說(shuō)是變量d等于匿名函數(shù)。而這個(gè)匿名函數(shù)因?yàn)槭褂昧撕瘮?shù)a中的變量b并且還被變量d所引用,所以就形成了一個(gè)閉包,只要這個(gè)變量d不等于null的話,那么那個(gè)變量b會(huì)一直保存到變量d中不會(huì)被銷(xiāo)毀。

總結(jié):

1、如果一個(gè)對(duì)象不被引用,那么這個(gè)對(duì)象就會(huì)被GC回收;
2、如果兩個(gè)對(duì)象互相引用,但是沒(méi)有被第3個(gè)對(duì)象所引用,那么這兩個(gè)互相引用的對(duì)象也會(huì)被回收。

參考文章:
1.初識(shí)js中的閉包
2.從閉包案例中學(xué)習(xí)閉包的作用,會(huì)不會(huì)由你
3.那些年我們一起過(guò)的JS閉包,作用域,this,讓我們一起劃上完美的句號(hào)
4.再次講解js中的回收機(jī)制是怎么一回事。

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

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

相關(guān)文章

  • 【進(jìn)階1-4期】JavaScript深入之帶你走進(jìn)內(nèi)存機(jī)制

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

    不知名網(wǎng)友 評(píng)論0 收藏0
  • 段代碼,帶你理解js執(zhí)行上下文的工作流程

    摘要:由于函數(shù)被調(diào)用了,線程會(huì)從剛剛保存的變量中取出內(nèi)容,去解析執(zhí)行它。最后,當(dāng)線程遇到離開(kāi)上下文的標(biāo)識(shí),便離開(kāi)上下文,并把的結(jié)果一并返回出去。 原文鏈接,歡迎關(guān)注我的博客 我相信很多前端初學(xué)者一開(kāi)始都會(huì)被執(zhí)行上下文這個(gè)概念弄暈,或者說(shuō)似懂非懂。對(duì)于工作兩年的我來(lái)說(shuō),說(shuō)來(lái)實(shí)在慚愧,雖然知道它大概是什么,但總覺(jué)得沒(méi)有一個(gè)更為清晰的認(rèn)識(shí)(無(wú)法把它的工作過(guò)程描述清楚),因此最近特意溫習(xí)了一遍,寫(xiě)下...

    developerworks 評(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
  • 帶你了解什么是JavaScript 函數(shù)式編程?

    摘要:前言函數(shù)式編程在前端已經(jīng)成為了一個(gè)非常熱門(mén)的話題。整個(gè)過(guò)程就是體現(xiàn)了函數(shù)式編程的核心思想通過(guò)函數(shù)對(duì)數(shù)據(jù)進(jìn)行轉(zhuǎn)換。高階函數(shù)函數(shù)式編程傾向于復(fù)用一組通用的函數(shù)功能來(lái)處理數(shù)據(jù),它通過(guò)使用高階函數(shù)來(lái)實(shí)現(xiàn)。 前言 函數(shù)式編程在前端已經(jīng)成為了一個(gè)非常熱門(mén)的話題。在最近幾年里,我們看到非常多的應(yīng)用程序代碼庫(kù)里大量使用著函數(shù)式編程思想。 本文將略去那些晦澀難懂的概念介紹,重點(diǎn)展示在 JavaScrip...

    acrazing 評(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

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

0條評(píng)論

閱讀需要支付1元查看
<