成人怡红院-成人怡红院视频在线观看-成人影视大全-成人影院203nnxyz-美女毛片在线看-美女免费黄

站長資訊網
最全最豐富的資訊網站

你必須了解的JavaScript閉包

本篇文章給大家帶來了關于JavaScript閉包的學習筆記,其中包括了閉包與方法棧以及閉包的作用,希望對大家有幫助。

你必須了解的JavaScript閉包

從定義上來講,它是一個腳本語言,而且是一個相對容易學習的腳本語言。不需要太多的專業知識,你也能夠在一定程度上使用js(JavaScript的簡寫)代碼。

當然如果你已經學習了一前端知識,你應該能理解這個工具的作用,這是一個非常方便的顯示頁面元素之間間距的工具。你看,你僅僅是進行了一些簡單的瀏覽器操作,甚至你無法理解上述代碼的內容,但你剛剛確確實實的嵌入了一段js代碼在你所在的頁面中(顯然它是無害的,請放心使用)感謝up主CodingStartup起碼課的視頻【有了它,把網頁做到跟設計圖一樣】以及up主ArcRain在視頻下方的回復

這篇學習筆記的目的是記錄我自己對于js學習路程中的一些感悟和體會,以及一些我自己認為的小技巧,而不是為了教學,所以其中的部分內容的原理我并不會給出答案,有可能是我沒法準確的描述,有可能是我還沒弄懂,本人水平相當有限,如果文字中有錯誤的部分歡迎大家指摘。

1. 學習JavaScript的契機

正式學習JavaScript是在培訓班,沒錯我是從培訓班出來的,并不是科班出身,可以說是非常的草根了。我學習的時候ES6標準還并未普及,變量命名還在用非常傳統的var,學習的第一段代碼是經典的console.log('Hello,world!'),當然它是在控制臺上打印出來的。

當然,在培訓機構中的JavaScript內容講的是非常的淺顯,只有最為基礎的變量定義與命名,function聲明,回調函數,ajax以及最為基礎的dom操作。顯然這些內容對于工作完全不夠用的。

對于js學習的‘進修’機會來源于我的工作,在工作中我第一次知道了node這個東西,也了解到即便是js也是可以做后臺的(我是做的JAVA培訓),也開始逐漸接觸到了一些ES6的標準。當然這些都是后話,最開始我接觸到最大的障礙是這貨。

2.‘惡心’的閉包

啊,對我只有那么一丁丁點基礎的我,完全無法理解我們公司自己封裝的jsonp代碼,它是長這個樣子的。

  var jsonp = (function(){         var JSONP;        return function(url){            if (JSONP) {              document.getElementsByTagName("head")[0].removeChild(JSONP);           }          JSONP = document.createElement("script");           JSONP.type = "text/javascript";           JSONP.src = url;           document.getElementsByTagName("head")[0].appendChild(JSONP);        }      }())

當然,現在瀏覽器上已經無法通過控制臺直接使用這個方法了,為了防止XSS攻擊瀏覽器已經禁止這樣注入代碼了,但是在服務器上還是可以用的,當然,這些都不是重點。

重點是這里

    if (JSONP) {        //dosome  }

如果你和我當初一樣,不知道什么叫閉包或者對閉包一知半解,那么,對于這里你應該也會產生疑問,思路大約是這樣的

第2行定義了JSONP但是沒有賦值,現在JSONP值為null,第三行返回了一個方法,第四行檢測JSONP值是否為空,如果不為空則做了一些事情,好了,后面可以不用看了,這個if白寫了,它百分百進不去!

你看嘛,前面也沒有賦值,然后直接判斷,那它明明就是null。但是實際使用的時候你會發現,這個地方第一次調用確實不會進入這個分支,但只要你調用了第二次,,它就百分百會進入這個分支。

// 這個是一個可以在控制臺輸出的閉包版本,你可以自己試一下 var closedhull = (function() {     let name = null; // 這里直接賦值為null     return function(msg){         if(name) {             console.log('name:', name)             return name += msg;         }         return name = msg;     } }()) closedhull('我是第一句。') //我是第一句。 closedhull('我是第二句。') //我是第一句。我是第二句。

上面這個例子運行后,無論是從console.log()亦或是返回值上都不難看出,確實進入了if(name)的分支,這個就是閉包的表現。這里給出一下閉包的定義

閉包就是能夠讀取其他函數內部變量的函數。

3.閉包的樣子到底是什么樣的

好了,看過閉包是個啥了,先不說會不會用,至少,算是見過了,閉包有個顯著的特征return function(){}

不是!

它的顯著特征是在function內的function!

觀察以下方法

/*第一個案例*/ function test1(){     // a應該在方法運行結束后銷毀     let a = 1;     return {         add: function(){             return ++a;         }     } } let a = test1(); a.add()//2 a.add()//3 /*第二個案例*/ (function(){     // b應該在方法運行結束后銷毀     let b = 1,         timer = setInterval(()=>{         console.log(++b)     }, 2000)     setTimeout(()=>{         clearInterval(timer)     }, 10000) })()// 2 3 4 5 6 /*第三個案例*/ function showMaker(obj){     // obj應該在方法運行結束后銷毀     return function(){         console.log(JSON.stringify(obj))     } } let shower = showMaker({a:1}) // 顯然這里你還能看到他 shower(); // {"a":1} /*第四個案例*/ let outObj = (function(){     let c = 'hello',         obj = {};     Object.defineProperty(obj, 'out', {         get(){             return c;         },         set(v){             c = v;         }     });     return obj })() outObj.out // 可以讀取并設置c的值

這四個都是閉包,他們都具備方法中的方法這一特性。

4.閉包與方法棧(對原理不感興趣可以略過)

閉包的定義,1. 可以在變量的作用域外訪問該變量。2. 通過某種手段延長一個局部變量的生命周期。3. 讓一個局部變量的存活時間超過它的時間循環執行時間

3中由于涉及到了事件循環概念,之后涉及到時會去講的,這里主要討論前兩種方式的定義。

一下內容如果你知道方法棧是個啥了就可以跳過了

局部作用域:在ES6之前,一般指一個方法內部(從參數列表開始,到方法體的括號結束為止),ES6中增加let關鍵字后,在使用let的情況下是指在一個{}中的范圍內(顯然,你不能在隱式的{}中使用let,編譯器會禁止你做出這種行為的,因為沒有{}就沒有塊級作用域),咱們這里為了簡化討論內容,暫且不把let的塊級作用域算作閉包的范疇(其實應該算,不過意義不大,畢竟,你可以在外層塊聲明它。天啊,JS的命名還沒擁擠到需要在一個方法內再去防止污染的程度。)

局部變量:區別于全局變量,全局變量會在某些時候被意外額創造和使用,這令人非常的…惱火和無助。局部變量就是在局部作用域下使用變量聲明關鍵字聲明出來的變量,應該很好理解。

局部變量的生命周期:好了,你在一個局部作用域中通過關鍵字(var const let等)聲明了一個變量,然后給它賦值,這個局部變量在這個局部作用域中冒險就開始了,它會被使用,被重新賦值(除了傲嬌的const小姐外),被調用(如果它是個方法),這個局部變量的本質是一個真實的值,區別在于如果它是個對象(對象,數組,方法都是對象)那么,它其實本質是一個地址的指針。如果它一個基礎類型,那么它就是那個真實的值。它之所以存活是因為它有個住所。內存。

局部作用域與內存:每當出現一個局部作用域,一個方法棧就被申請了出來,在這個方法棧大概長這樣子

|  data5 | |  data4 | |  data3 | |  data2 | |__data1_|

當然,它是能夠套娃的,長這個樣子

|  | d2 |  | |  |_d1_|  | |  data3   | |  data2   | |__data1___|

如果上面的東西是在太過于抽象,那么,我可以用實際案例展示一下

function stack1(){     var data1,         data2,         data3,         data4,         data5 } function stack2(){     var data1,         data2,         data3;     function stackInner(){         var d1,             d2;     } }

如果方法棧能夠直觀的感受的話,大約就是這個樣子,咱們重點來分析stack2的這種情況,同時寫一點實際內容進去

function stack2(){     var data1 = '1',         data2 = {x: '2'},         data3 = '3';     function stackInner(){         var d1 = '4',             d2 = {y: '5'};     }     stackInner() } stack2()

顯然其中data1,data3,d1持有的是基本類型(string),data2,d2持有的是引用類型(object),反應到圖上

運行時的方法棧的樣子

            |------>{y: '5'}             |    |->{x: '2'}     |  | d2-|   || |     |  |_d1='4'_|| |     |  data3='3' | |     |  data2 ----| |     |__data1='1'___|

畫有點抽象…就這樣吧。具體對象在哪呢?他們在一個叫堆的地方,不是這次的重點,還是先看方法棧內的這些變量,運行結束后,按照先進后出的原則,把棧內的局部變量一個一個的銷毀,同時堆里的兩個對象,由于引用被銷毀,沒了繼續存在的意義,等待被垃圾回收。

接下來咱們要做兩件事情:

  • d1不再等于4了,而是引用data1

  • return stackInner 而不是直接調用

這樣閉包就完成了

function stack2(){     var data1 = {msg: 'hello'},         data2 = {x: '2'},         data3 = '3';     function stackInner(){         var d1 = data1,             d2 = {y: '5'};     }     return stackInner } var out = stack2()

這里有一個要點,d2賦值給data1一定是在stackInner中完成的,原因?因為再stackInner方法中d2才被聲明出來,如果你在stack2中d1 = data1那么恭喜你,你隱式的聲明了一個叫d1的全局變量,而且在stackInner由于變量屏蔽的原因,你也看不到全局上的d2,原本計劃的閉包完全泡湯。

變量屏蔽:不同作用域中相同名稱的變量就會觸發變量屏蔽。

看看?,F在的樣子

運行時的方法棧的樣子

               |------>{y: '5'} out<---|       | |----|     |  |  | d2-| | |  |  |     |  |--|_d1---|_|  |  |     |     data3='3'   |  |     |     data2(略)   |  |     |_____data1<------|__|

好了,這個圖可以和我們永別了,如果有可能,我后面會用畫圖工具替代,這么畫圖實在是太過邪典了。

這里涉及到了方法棧的一個特性,就是變量的穿透性,外部變量可以在內部的任意位置使用,因為再內部執行結束前,外部變量會一直存在。

由于stackInner被外部的out引用,導致這個對象不會隨著方法棧的結束而銷毀,接下來,最神奇的事情來了,由于stackInner這對象沒有銷毀,它內部d1依然保有data1所對應數據的引用,d1,d2一定會活下來,因為他們的爸爸stackInner活下來了,data1也以某種形式活了下來。

為什么說是某種形式,因為,本質上來說data1還是被銷毀了。沒錯,只不過,data1所引用的那個對象的地址鏈接沒有被銷毀,這個才是本質。棧在調用結束后一定是會銷毀的。但是調用本體(方法對象)只要存在,那么內部所引用的鏈接就不會斷。

這個就是閉包的成因和本質。

5.閉包有什么用

OK,我猜測上一個章節估計很多人都直接跳過了,其實,跳過影響也不多,這個部分描述一下結論性的東西,閉包的作用。

它的最大作用就是給你的變量一個命名空間,防止命名沖突。要知道,你的框架,你export的東西,你import進來的東西,在編譯的時候都會變成閉包,為的就是減少你變量對全局變量的污染,一個不依賴與import export的模塊的代碼大概長這個樣子

(function(Constr, global){     let xxx = new Constr(env1, env2, env3)     global.NameSpace = xxx; })(function(parm1, parm2, parm3) {     //dosomeing     reutrn {         a: 'some1',         b: 'some2',         funcC(){             //dosome         },         funcD(){             //dosome         }     } }, window)

當然這種封裝代碼的風格有多種多樣的,但是大家都盡量把一套體系的內容都放到一個命名空間下,避免與其他框架產生沖突

贊(0)
分享到: 更多 (0)
?
網站地圖   滬ICP備18035694號-2    滬公網安備31011702889846號
亚洲精品无码一区二区AⅤ污| 亚洲欧美综合区丁香五月小说 | 久久无码国产专区精品| 老头猛挺进小雯的体内视频| 免费A级毛片18禁网站APP| 男女啪啪吃奶GIF动态图| 欧美最猛性XXXXX大叫| 日韩成人无码中文字幕| 同桌上课脱裙子让我帮他自慰| 小说蜜汁樱桃林妙妙的结局| 亚洲国产精品一区第二页| 亚洲综合色区在线观看| 99国精产品灬源码1688钻| 草莓视频免费观看| 国产成人亚洲综合A∨| 海角国精产品三区二区三区| 久久久国产精品消防器材| 蜜臀AV一区二区三区四区| 日本成熟人妻HD| 我半夜摸妺妺的奶摸到高潮 | 日本工口里番H全彩无遮挡| 无码AⅤ精品一区二区三区浪潮| 亚洲AV永久无码天堂网毛片| 制服丝袜人妻中文字幕在线| 939W78W78W乳液特色| 丰满妇女伦大片免费| 黑人大战中国AV女叫惨了| 老汉引诱新婚少妇| 日本老熟妇毛茸茸| 亚洲AV丁香五月六月婷婷 | 久久精品国产一区二区三| 欧美老熟妇乱大交XXXXX| 天堂AV男人在线播放| 亚洲AV自慰白浆喷水网站少妇| 真实的国产乱ⅩXXX66小说| 超碰97人人做人人爱2020| 国产偷窥熟女精品视频大全| 老公带朋友来家里C我怎么办 | 啊灬啊灬啊灬快灬深视频无遮掩| 国产乱子伦农村XXXX| 久久亚洲精品成人AV无码涩涩屋| 人人爽天天碰狠狠添| 亚洲AV无码专区青青草原| 6080电影网站| 国产精品久久久久久一区二区三区| 久久久久久精品国产亚洲AV麻豆 | 天天想你视频免费观看西瓜| 亚洲香蕉成人AV网站在线观看| 宝宝都湿透了还嘴硬疼怎么回事| 国精品无码一区二区三区在线蜜臀 | 久久亚洲日韩成人无码导航| 色欲综合久久躁天天躁| 亚洲午夜福利精品久久| 出租屋勾搭老熟妇啪啪| 黑人大战亚洲女精品区| 欧美性XXXX极品少妇| 羞羞漫画AⅤ漫画AV漫画视频| 97人妻人人做人碰人人爽| 国产精品免费看久久久无码| 蜜臀AⅤ永久无码精品| 小SAO货CAO得你舒服么| JAPANESE人妻少妇| 精品国产A∨无码一区二区三区| 日本极品少妇XXXX| 亚洲香蕉成人AAAV在线网站| 国产AV无码专区亚洲AV果冻传| 麻豆国产在线精品国偷产拍 | 国产成人69视频午夜福利在线观| 久久这里只精品国产免费9| 婷婷开心色四房播播| 337P大胆啪啪私拍人体| 荷兰肥妇BBWBBWBBW| 日韩精品成人一区二区三区| 一女大战七个黑人到喷浆| 国产精品国产精品国产专区不卡| 精品少妇人妻av免费久久洗澡| 日韩人妻无码一区二区三区视频 | 人妻丰满熟妇AⅤ无码区| 亚洲欧好州第一的日产SUV| 大香伊蕉在人线国产最新75| 久久综合无码中文字幕无码TS| 我的真實亂倫故事| AV色欲无码人妻中文字幕| 国产自国产自愉自愉免费24区| 人妻少妇偷人精品无码| 亚洲中文字幕乱码AV波多JI| 国产成人无码A区在线观看视频| 免费无码一区二区三区蜜桃| 亚洲AV无码专区在线电影| 成人亚洲区无码区在线点播| 鲁一鲁AV2019在线| 小12国产萝裸体视频福利| 成人国产精品一区二区网站免费 | 日本熟妇人妻ⅩXXXXOO多毛| 夜夜添夜夜添夜夜摸夜夜摸| 国产美女裸体无遮挡免费视频| 人妻 清高 无码 中文字幕| 野花日本大全免费观看10中文| 国产精品民宅偷窥盗摄| 日本护士体内SHE精2╳╳╳| 亚洲欧洲专线一区| 国产AV一区二区精品久久| 秋霞AV鲁丝片一区二区| 岳今晚让我玩个够肥水一体探岳体| 国产真实强被迫伦姧女在线观看| 日本中文字幕一区二区有码在线| 装醉把自己给流浪汉玩| 久久精品国产亚洲AV麻豆软件 | 牛鞭进入女人下身的视频| 亚洲中文字幕久久无码精品| 国产熟女高潮精品视频区| 女人张开腿扒开内裤让男生桶| 野花大全在线观看免费高清| 国产无遮挡无码视频免费软件 | 国产成A人亚洲精V品无码性色| 日本在线 | 中文| CHINESEVIDEO性大全| 蜜臀av夜夜嗨一区二区粉嫩| 亚洲色成人网站WWW永久小说| 国产综合在线观看| 无码国产伦一区二区三区视频| 俄罗斯1317大但人文艺术| 奶头被民工们吸得又红又肿怎么办| 亚洲国产精品久久久久婷婷图片| 国产精品久久久久AV| 丝袜一区二区三区在线播放| 成人国产精品秘片多多| 欧洲美女黑人粗性暴交视频| 18禁男女爽爽爽午夜网站免费| 久久中文字幕AV一区二区不卡| 亚洲日韩精品无码专区网址| 国产精品久久久久AV| 午夜男女爽爽羞羞影院在线观看| 国产WW久久久久久久久久| 少女たちよ在线观看完整版动漫 | 欧洲成人一区二区三区| 永久免费观看国产裸体美女 | 亚洲精品亚洲人成在线| 好大好爽舔我高潮了| 亚洲AV无码久久精品蜜桃| 国产在线精品无码二区二区| 婷婷综合缴情亚洲狠狠| 国产极品视觉盛宴专区| 我和几个亲戚都做了爱| 国产精品人成在线播放新网站| 婷婷色丁香伊人中文| 国产成人啪精品视频免费网站软件| 特大荫唇XX另类| 国产精华液一线二线三线 | 蜜桃AV无码乱码精品| 中文字幕乱偷无码av先锋蜜桃| 男人吃奶摸下挵进去好爽在线观看| 4HUWWW四虎永久免费| 欧美人与劲物XXXXZ0OZ| YYYY1111111午夜少妇| 日本爆乳片手机在线播放| 宝贝儿感受到它对你的爱了吗小说 | GAYFUCKⅩⅩⅩⅩHD激情| 青青草原精品国产亚洲AV| 当着老公的面被别人欺负该怎么办 | 欧洲人妻丰满AV无码久久不卡 | 亚洲精品无码久久久久AV麻豆| 九九爱WWW免费人成视频| 一区国产情侣宾馆射| 女生输了给对方玩一个月| 八戒八戒神马影院在线4| 日产无人区一线二线三线小说| 国产AV无码精品色午夜| 午夜成人无码免费看网站| 娇小的学生BBW18| 在线观看的AV网站| 欧美黑人又大又粗高潮喷水| 成人国产精品一区二区网站免费 | 精品国产成人国产在线观看| 曰本无码人妻丰满熟妇啪啪| 女主播屁G裸露W身曝光| 草木影视在线视频免费观看| 无码人妻精品中文字幕| 精品日本一区二区三区免费| 中文字幕无码无码专区| 欧美最猛性XXXXX免费| 国产成人无码免费视频79| 亚洲国产精品无码久久久 | 老少配XXOO老少配| 波多野结衣av电影在线观看| 无码人妻AⅤ一区二区| 久久99精品国产99久久6尤物| 最新版天堂资源网在线种子| 日日狠狠久久8888偷偷色| 国内精品久久人妻无码网站| 在线观看内射亲妹妹无套内射| 人妻少妇精品久久久久久0000 | 亚洲精品成人网站在线| 妺妺窝人销魂体色www| 出轨 无码 论坛| 亚洲国产成人资源在线| 欧美VA久久久噜噜噜久久| 国产精品美女久久久免费| 尹人香蕉久久99天天拍| 日韩人妻一区二区三区免费|