gmnon.cn-疯狂蹂躏欧美一区二区精品,欧美精品久久久久a,高清在线视频日韩欧美,日韩免费av一区二区

站長資訊網(wǎng)
最全最豐富的資訊網(wǎng)站

你必須了解的JavaScript閉包

本篇文章給大家?guī)砹岁P(guān)于JavaScript閉包的學(xué)習(xí)筆記,其中包括了閉包與方法棧以及閉包的作用,希望對大家有幫助。

你必須了解的JavaScript閉包

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

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

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

1. 學(xué)習(xí)JavaScript的契機(jī)

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

當(dāng)然,在培訓(xùn)機(jī)構(gòu)中的JavaScript內(nèi)容講的是非常的淺顯,只有最為基礎(chǔ)的變量定義與命名,function聲明,回調(diào)函數(shù),ajax以及最為基礎(chǔ)的dom操作。顯然這些內(nèi)容對于工作完全不夠用的。

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

2.‘惡心’的閉包

啊,對我只有那么一丁丁點基礎(chǔ)的我,完全無法理解我們公司自己封裝的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);        }      }())

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

重點是這里

    if (JSONP) {        //dosome  }

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

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

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

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

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

閉包就是能夠讀取其他函數(shù)內(nèi)部變量的函數(shù)。

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

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

不是!

它的顯著特征是在function內(nèi)的function!

觀察以下方法

/*第一個案例*/ function test1(){     // a應(yīng)該在方法運(yùn)行結(jié)束后銷毀     let a = 1;     return {         add: function(){             return ++a;         }     } } let a = test1(); a.add()//2 a.add()//3 /*第二個案例*/ (function(){     // b應(yīng)該在方法運(yùn)行結(jié)束后銷毀     let b = 1,         timer = setInterval(()=>{         console.log(++b)     }, 2000)     setTimeout(()=>{         clearInterval(timer)     }, 10000) })()// 2 3 4 5 6 /*第三個案例*/ function showMaker(obj){     // obj應(yīng)該在方法運(yùn)行結(jié)束后銷毀     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 // 可以讀取并設(shè)置c的值

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

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

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

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

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

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

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

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

局部作用域與內(nèi)存:每當(dāng)出現(xiàn)一個局部作用域,一個方法棧就被申請了出來,在這個方法棧大概長這樣子

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

當(dāng)然,它是能夠套娃的,長這個樣子

|  | 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的這種情況,同時寫一點實際內(nèi)容進(jìn)去

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īng)到圖上

運(yùn)行時的方法棧的樣子

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

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

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

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

  • return stackInner 而不是直接調(diào)用

這樣閉包就完成了

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ā)變量屏蔽。

看看棧現(xiàn)在的樣子

運(yùn)行時的方法棧的樣子

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

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

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

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

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

這個就是閉包的成因和本質(zhì)。

5.閉包有什么用

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

它的最大作用就是給你的變量一個命名空間,防止命名沖突。要知道,你的框架,你export的東西,你import進(jìn)來的東西,在編譯的時候都會變成閉包,為的就是減少你變量對全局變量的污染,一個不依賴與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)

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

贊(0)
分享到: 更多 (0)
網(wǎng)站地圖   滬ICP備18035694號-2    滬公網(wǎng)安備31011702889846號
gmnon.cn-疯狂蹂躏欧美一区二区精品,欧美精品久久久久a,高清在线视频日韩欧美,日韩免费av一区二区
免费不卡av网站| 91亚洲精品久久久蜜桃借种| 国产精品拍拍拍| 精品免费国产一区二区| 99久久久无码国产精品6| 肉大捧一出免费观看网站在线播放| www.欧美激情.com| 成人在线观看毛片| 日本丰满大乳奶| 国产精品免费入口| 国产成年人视频网站| 一道本在线观看视频| 国产美女网站在线观看| 无限资源日本好片| 久久久久久av无码免费网站下载| 成人黄色av片| 永久免费黄色片| 日本xxxxx18| 久色视频在线播放| 国产一级做a爰片久久| 91精品视频国产| cao在线观看| 黄色高清视频网站| 黄色三级视频片| 美女日批免费视频| 香蕉视频网站入口| 中文字幕の友人北条麻妃| 久艹视频在线免费观看| 色哟哟精品视频| 国产成人永久免费视频| 国产高清精品软男同| 人体内射精一区二区三区| 久草在在线视频| 日韩在线一级片| 亚洲激情在线看| 国产亚洲欧美在线视频| 日本黄色播放器| 免费av网址在线| 800av在线免费观看| 色婷婷成人在线| aa在线观看视频| 三级在线免费观看| 久久久久久久久久一区二区| 日本福利视频在线观看| 日韩肉感妇bbwbbwbbw| 免费看欧美一级片| 亚洲va综合va国产va中文| www国产精品内射老熟女| 色男人天堂av| 第一区免费在线观看| 国产一级不卡毛片| 男人日女人逼逼| 免费看日本毛片| 人妻互换免费中文字幕| 一级片免费在线观看视频| 国产一区二区视频免费在线观看 | 全黄性性激高免费视频| 免费网站在线观看黄| 亚洲最大综合网| 91蝌蚪视频在线观看| 97xxxxx| 免费日韩视频在线观看| 大伊香蕉精品视频在线| 国产精品一二三在线观看| 在线能看的av网站| 美女网站色免费| 一区二区三区视频在线观看免费| 久久婷婷五月综合色国产香蕉| 日韩国产小视频| 国产一区二区三区小说| 拔插拔插海外华人免费| 国产日韩欧美精品在线观看| 妞干网在线观看视频| 成人在线观看你懂的| 波多野结衣家庭教师在线| 青青青免费在线| caopor在线视频| 黄色手机在线视频| 一路向西2在线观看| 天堂av在线8| 日韩人妻精品一区二区三区| 国产av熟女一区二区三区| 你真棒插曲来救救我在线观看| 免费无遮挡无码永久视频| 成年人黄色片视频| 天天综合天天添夜夜添狠狠添| 国产精品无码乱伦| 日本xxxxxxxxxx75| 色悠悠久久综合网| 亚洲欧美日韩网站| 男人插女人视频在线观看| 国产精品wwwww| 中文字幕线观看| 91好吊色国产欧美日韩在线| 日本免费黄视频| 国产一级免费大片| 国产免费黄色小视频| 亚洲一级片免费| 日韩极品视频在线观看| 美女少妇一区二区| 女人被男人躁得好爽免费视频| 欧美丰满熟妇xxxxx| 亚洲激情免费视频| 色综合色综合色综合色综合| 国产a级黄色大片| 日本中文字幕精品—区二区| 青青草国产免费| 日本黄色福利视频| 三上悠亚久久精品| 在线观看18视频网站| 91精品无人成人www| 日本欧美视频在线观看| 亚洲理论中文字幕| 国产视频一区二区三区在线播放 | 9色porny| 免费成人进口网站| 国产三级精品三级在线| 日本精品一区二区三区四区| 亚洲小说欧美另类激情| 亚洲最大天堂网| 精品免费国产一区二区| 精品久久一二三| www.日本在线视频| 日本免费成人网| 毛片在线视频观看| 路边理发店露脸熟妇泻火| 亚洲天堂av一区二区| 粉色视频免费看| 91插插插插插插插插| 欧美日韩在线成人| www.欧美日本| 99视频免费播放| 最新中文字幕免费视频| 老司机午夜av| 污色网站在线观看| 天天做天天干天天操| 一区二区三区免费播放| 欧美大尺度做爰床戏| 成人综合久久网| 免费不卡av网站| 亚洲色婷婷久久精品av蜜桃| 五月天在线免费视频| 日韩免费在线观看av| 青青青免费在线| 青青青国产在线视频| 欧美国产日韩另类| 国产在线视频综合| 青青艹视频在线| 天堂在线资源视频| 婷婷视频在线播放| 91网站在线观看免费| 日韩精品视频久久| 特黄视频免费观看| 青青青青在线视频| 一本久道中文无码字幕av| 不卡的在线视频| 东北少妇不带套对白| 不卡av免费在线| 久久久久久久久影视| 国产91美女视频| 亚洲视频第二页| 人体内射精一区二区三区| 九九热免费精品视频| 国产激情在线看| 男女啪啪网站视频| 日本免费成人网| 欧美一级视频在线| 欧美日韩性生活片| 天堂av免费看| 999精品网站| 国产精品一二三在线观看| 92看片淫黄大片一级| 中国一级黄色录像 | 亚洲妇熟xx妇色黄蜜桃| 国精产品一区一区三区视频| 亚洲怡红院在线| 国产91在线视频观看| 喜爱夜蒲2在线| 日本不卡一区二区在线观看| 国产中文字幕二区| 性生活免费观看视频| 免费看国产黄色片| 欧美视频第一区| 欧美精品久久久久久久自慰| 男女爱爱视频网站| 亚洲涩涩在线观看| 色综合手机在线| 91在线视频观看免费| 欧美亚洲另类色图| 亚洲 欧美 日韩 国产综合 在线 | 国产91沈先生在线播放| 国产a级片免费看| 午夜久久福利视频| 中文字幕第38页| www.久久91| 嫩草影院国产精品| 超碰超碰在线观看| 日本在线观看免费视频| 天天影视综合色| 日本国产一级片|