這篇文章給大家分享的是有關(guān)JS閉包可被利用的常見場(chǎng)景有哪些的內(nèi)容。小編覺得挺實(shí)用的,因此分享給大家做個(gè)參考,一起跟隨小編過來看看吧。
成都創(chuàng)新互聯(lián)是一家專注網(wǎng)站建設(shè)、網(wǎng)絡(luò)營銷策劃、小程序定制開發(fā)、電子商務(wù)建設(shè)、網(wǎng)絡(luò)推廣、移動(dòng)互聯(lián)開發(fā)、研究、服務(wù)為一體的技術(shù)型公司。公司成立十多年以來,已經(jīng)為成百上千成都辦公空間設(shè)計(jì)各業(yè)的企業(yè)公司提供互聯(lián)網(wǎng)服務(wù)?,F(xiàn)在,服務(wù)的成百上千客戶與我們一路同行,見證我們的成長;未來,我們一起分享成功的喜悅。
場(chǎng)景一:采用函數(shù)引用方式的setTimeout調(diào)用
閉包的一個(gè)通常的用法是為一個(gè)在某一函數(shù)執(zhí)行前先執(zhí)行的函數(shù)提供參數(shù)。例如,在web環(huán)境中,一個(gè)函數(shù)作為setTimeout函數(shù)調(diào)用的第一個(gè)參數(shù),是一種很常見的應(yīng)用。
setTimeout
將要執(zhí)行的函數(shù)(或者一段JavaScript代碼,但這不是我們要討論的情況)作為它的第一個(gè)參數(shù),下一個(gè)參數(shù)是需要延遲執(zhí)行的時(shí)間。如果一段代碼想通過setTimeout來調(diào)用,那么它需要傳遞一個(gè)函數(shù)對(duì)象的引用來作為第一個(gè)參數(shù)。延遲的毫秒數(shù)作為第二個(gè)參數(shù),但這個(gè)函數(shù)對(duì)象的引用無法為將要被延遲執(zhí)行的對(duì)象提供參數(shù)。
但是,可以調(diào)用另一個(gè)函數(shù)來返回一個(gè)內(nèi)部函數(shù)的調(diào)用,將那個(gè)內(nèi)部函數(shù)對(duì)象的引用傳遞給setTimeout函數(shù)。內(nèi)部函數(shù)執(zhí)行時(shí)需要的參數(shù),在調(diào)用外部函數(shù)時(shí)傳遞給它。setTimeout在執(zhí)行內(nèi)部函數(shù)時(shí)無需傳遞參數(shù),因?yàn)閮?nèi)部函數(shù)仍然能夠訪問外部函數(shù)調(diào)用時(shí)提供的參數(shù):
function callLater(paramA, paramB, paramC) { /*使用函數(shù)表達(dá)式創(chuàng)建并放回一個(gè)匿名內(nèi)部函數(shù)的引用*/ return (function () { /* 這個(gè)內(nèi)部函數(shù)將被setTimeout函數(shù)執(zhí)行; 并且當(dāng)它被執(zhí)行時(shí), 它能夠訪問并操作外部函數(shù)傳遞過來的參數(shù) */ paramA[paramB] = paramC; }); } /* 調(diào)用這個(gè)函數(shù)將在它的執(zhí)行上下文中創(chuàng)建,并最終返回內(nèi)部函數(shù)對(duì)象的引用 傳遞過來的參數(shù),內(nèi)部函數(shù)在最終被執(zhí)行時(shí),將使用外部函數(shù)的參數(shù) 返回的引用被賦予了一個(gè)變量 */ var funcRef = callLater(elStyle, "display", "none"); /*調(diào)用setTimeout函數(shù),傳遞內(nèi)部函數(shù)的引用作為第一個(gè)參數(shù)*/ hideMenu = setTimeout(funcRef, 500);
場(chǎng)景二:將函數(shù)關(guān)聯(lián)到對(duì)象的實(shí)例方法
有很多這樣的場(chǎng)景:需要分配一個(gè)函數(shù)對(duì)象的引用,以便在未來的某個(gè)時(shí)間執(zhí)行該函數(shù)。那么閉包對(duì)于為這個(gè)將要執(zhí)行的函數(shù)提供引用會(huì)非常有幫助。因?yàn)樵摵瘮?shù)可能直到執(zhí)行時(shí)才能夠被訪問。
有一個(gè)例子就是,一個(gè)javascript對(duì)象被封裝用來參與一個(gè)特定DOM元素的交互。它有doOnClick、doMouseOver以及doMouseOut方法。并且想在DOM元素上對(duì)應(yīng)的事件被觸發(fā)時(shí)執(zhí)行這些方法。但是,可能會(huì)有關(guān)聯(lián)著DOM元素的任意數(shù)量的javascript對(duì)象被創(chuàng)建,并且單個(gè)的實(shí)例并不知道那些實(shí)例化它們的代碼將如何處理它們。對(duì)象實(shí)例不知道怎樣去“全局”地引用它們自己,因?yàn)樗鼈儾恢滥膫€(gè)全局變量(如果存在)的引用將被分配給它們。
所以,問題是執(zhí)行一個(gè)與特定javascript對(duì)象實(shí)例關(guān)聯(lián)的事件處理函數(shù),并且知道調(diào)用那個(gè)對(duì)象的哪個(gè)方法。
接下來的一個(gè)例子,在有元素事件處理的對(duì)象實(shí)例的關(guān)聯(lián)函數(shù)上使用一個(gè)簡單的閉包。通過傳遞event對(duì)象以及要關(guān)聯(lián)元素的一個(gè)引用,為事件處理器分配不同的對(duì)象實(shí)例方法以供調(diào)用。
/* 一個(gè)給對(duì)象實(shí)例關(guān)聯(lián)一個(gè)事件處理器的普通方法, 返回的內(nèi)部函數(shù)被作為事件的處理器, 對(duì)象實(shí)例被作為obj參數(shù),對(duì)象上將要被調(diào)用的方法名稱被作為第二個(gè)參數(shù) */ function associateObjWithEvent(obj, methodName) { /*返回的內(nèi)部函數(shù)被用來作為一個(gè)DOM元素的事件處理器*/ return (function (e) { /* 事件對(duì)象在DOM標(biāo)準(zhǔn)的瀏覽器中將被轉(zhuǎn)換為e參數(shù), 如果沒有傳遞參數(shù)給事件處理內(nèi)部函數(shù),將統(tǒng)一處理成IE的事件對(duì)象 */ e = e || window.event; /* 事件處理器調(diào)用obj對(duì)象上的以methodName字符串標(biāo)識(shí)的方法 并傳遞兩個(gè)對(duì)象:通用的事件對(duì)象,事件處理器被訂閱的元素的引用 這里this參數(shù)能夠使用,因?yàn)閮?nèi)部函數(shù)已經(jīng)被執(zhí)行作為事件處理器所在元素的一個(gè)方法 */ return obj[methodName](e, this); }); } /* 這個(gè)構(gòu)造器函數(shù),通過將元素的ID作為字符串參數(shù)傳遞進(jìn)來, 來創(chuàng)建將自身關(guān)聯(lián)到DOM元素上的對(duì)象, 對(duì)象實(shí)例想在對(duì)應(yīng)的元素觸發(fā)onclick、onmouseover、onmouseout事件時(shí) 對(duì)應(yīng)的方法被調(diào)用。 */ function DhtmlObject(elementId) { /* 調(diào)用一個(gè)方法來獲得一個(gè)DOM元素的引用 如果沒有找到,則為null */ var el = getElementWith(elementId); /* 因?yàn)閕f語句塊,el變量的值在內(nèi)部進(jìn)行了類型轉(zhuǎn)換,變成了boolean類型 所以當(dāng)它指向一個(gè)對(duì)象,結(jié)果就為true,如果為null則為false */ if (el) { /* 為了給元素指定一個(gè)事件處理函數(shù),調(diào)用了associateObjWithEvent函數(shù), 利用它自己(this關(guān)鍵字)作為被調(diào)用方法的對(duì)象,并且提供方法名稱 */ el.onclick = associateObjWithEvent(this, "doOnClick"); el.onmouseover = associateObjWithEvent(this, "doOnMouseOver"); el.onmouseout = associateObjWithEvent(this, "doOnMouseOut"); } } DhtmlObject.prototype.doOnClick = function (event, element) { //doOnClick body } DhtmlObject.prototype.doMouseOver = function (event, element) { //doMouseOver body } DhtmlObject.prototype.doMouseOut = function (event, element) { //doMouseOut body }
任何DhtmlObject的實(shí)例都能夠?qū)⑺鼈冏陨黻P(guān)聯(lián)到它們感興趣的DOM元素上去,不需要去擔(dān)心這些元素將被其他的代碼怎么處理,以及被全局命名空間“污染”或者與其他的DhtmlObject的實(shí)例產(chǎn)生沖突。
場(chǎng)景三:封裝相關(guān)的功能集
閉包可以創(chuàng)建額外的scope,這可以被用來組合相關(guān)的或有依賴性的代碼。用這種方式可以最大限度地減少代碼干擾的危害。假設(shè),一個(gè)函數(shù)被用來創(chuàng)建一個(gè)字符串并且避免重復(fù)串聯(lián)的操作(比如創(chuàng)建一系列的中間字符串)。一個(gè)想法是,用一個(gè)數(shù)組來順序存儲(chǔ)字符串的一部分,然后使用Array.prototype.join方法輸出結(jié)果(使用一個(gè)空字符串作為它的參數(shù))。數(shù)組將扮演著輸出緩沖區(qū)的角色,但局部定義它又將會(huì)導(dǎo)致它在函數(shù)的每次執(zhí)行時(shí)再次創(chuàng)建。如果這個(gè)數(shù)組只是作為唯一的變量被分配給每一個(gè)函數(shù)調(diào)用,這將會(huì)有點(diǎn)小題大做。
一個(gè)解決方案是將數(shù)組提升為全局變量,讓它不需要被再次創(chuàng)建也能夠再次使用。但結(jié)果并不是想的那么簡單,另外,一個(gè)全局變量關(guān)聯(lián)這使用緩沖數(shù)組的函數(shù),那將會(huì)有第二個(gè)全局屬性(函數(shù)本身也是window對(duì)象的屬性)關(guān)聯(lián)這個(gè)數(shù)組,這將讓代碼失去一定的可控性。因?yàn)槿绻麑⑺褂迷谄渌胤?。這段代碼的創(chuàng)建者不得不記住包含函數(shù)的定義以及數(shù)組的定義邏輯。它也使得代碼不那么容易與其他代碼整合,因?yàn)閷脑瓉碇恍枰_定函數(shù)名是否在全局命名空間中唯一,變成有必要確定和該函數(shù)關(guān)聯(lián)的數(shù)組的名稱是否在全局命名空間中保持唯一。
一個(gè)閉包可以讓緩沖數(shù)組關(guān)聯(lián)(干凈地包含)它依賴的函數(shù),并且同時(shí)保持緩沖數(shù)組的屬性名稱,像被分配在全局空間中一樣,同時(shí)能夠避免名稱沖突以及代碼交互干擾的危險(xiǎn)。
這里有一招就是通過執(zhí)行一個(gè)內(nèi)聯(lián)的函數(shù)表達(dá)式創(chuàng)建一個(gè)額外的執(zhí)行上下文,讓那個(gè)函數(shù)表達(dá)式返回一個(gè)內(nèi)聯(lián)的函數(shù),該函數(shù)被外部代碼使用。緩沖數(shù)組被定義在內(nèi)聯(lián)執(zhí)行的函數(shù)表達(dá)式中,作為一個(gè)局部變量。它僅被調(diào)用一次,所以該數(shù)組只被創(chuàng)建一次。但是對(duì)于依賴它的函數(shù)來說該數(shù)組是一直可訪問的,并且可被重用的。
接一下的代碼創(chuàng)建了一個(gè)函數(shù),將返回一個(gè)HTML字符串,其中的一部分是不變的,但那些不變的字符串需要被穿插進(jìn)作為參數(shù)傳遞進(jìn)來的變量中。
一個(gè)內(nèi)聯(lián)執(zhí)行的函數(shù)表達(dá)式返回了內(nèi)部函數(shù)對(duì)象的一個(gè)引用。并且分配了一個(gè)全局變量,讓它可以被作為一個(gè)全局函數(shù)來調(diào)用。而緩沖數(shù)組作為一個(gè)局部變量被定義在外部函數(shù)表達(dá)式中。它沒有被擴(kuò)展到全局命名空間中,并且無論函數(shù)什么時(shí)候使用它都不需要被再次創(chuàng)建。
/* 定義一個(gè)全局變量:getImgInPositionedDivHtml 被賦予對(duì)外部函數(shù)表達(dá)式一次調(diào)用返回的一個(gè)內(nèi)部函數(shù)表達(dá)式 內(nèi)部函數(shù)返回了一個(gè)HTML字符串,代表一個(gè)絕對(duì)定位的DIV 包裹這一個(gè)IMG元素,而所有的變量值都被作為函數(shù)調(diào)用的參數(shù) */ var getImgInPositionedDivHtml = (function () { /* buffAr 數(shù)組被定義在外部函數(shù)表達(dá)式中,作為一個(gè)局部變量 它只被創(chuàng)建一次。數(shù)組的唯一實(shí)例對(duì)內(nèi)部函數(shù)是可見的, 所以它可以被用于每一次的內(nèi)部函數(shù)執(zhí)行 空字符串僅僅被用來作為一個(gè)占位符,它將被內(nèi)部函數(shù)的參數(shù)代替 */ var buffAr = [ '<div id="', '', //index 1, DIV ID attribute '" style="position:absolute;top:', '', //index 3, DIV top position 'px;left:', '', //index 5, DIV left position 'px;width:', '', //index 7, DIV width 'px;height:', '', //index 9, DIV height 'px;overflow:hidden;\"><img src=\"', '', //index 11, IMG URL '\" width=\"', '', //index 13, IMG width '\" height=\"', '', //index 15, IMG height '\" alt=\"', '', //index 17, IMG alt text '\"><\/div>' ]; /* 返回一個(gè)內(nèi)部函數(shù)對(duì)象,他是函數(shù)表達(dá)式執(zhí)行返回的結(jié)果 */ return (function (url, id, width, height, top, left, altText) { /* 分配各種參數(shù)給對(duì)應(yīng)的數(shù)組元素 */ buffAr[1] = id; buffAr[3] = top; buffAr[5] = left; buffAr[13] = (buffAr[7] = width); buffAr[15] = (buffAr[9] = height); buffAr[11] = url; buffAr[17] = altText; /* 返回連接每個(gè)元素后創(chuàng)建的字符串 */ return buffAr.join(''); }); })();
如果一個(gè)函數(shù)依賴另一個(gè)或幾個(gè)函數(shù),但那些其他的函數(shù)并不期望與任何其他的代碼產(chǎn)生交互。那么這個(gè)簡單的技巧(使用一個(gè)對(duì)外公開的函數(shù)來擴(kuò)展那些函數(shù))就可以被用來組織那些函數(shù)。
感謝各位的閱讀!關(guān)于“JS閉包可被利用的常見場(chǎng)景有哪些”這篇文章就分享到這里了,希望以上內(nèi)容可以對(duì)大家有一定的幫助,讓大家可以學(xué)到更多知識(shí),如果覺得文章不錯(cuò),可以把它分享出去讓更多的人看到吧!
分享題目:JS閉包可被利用的常見場(chǎng)景有哪些
鏈接分享:http://muchs.cn/article36/ghhgpg.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供關(guān)鍵詞優(yōu)化、搜索引擎優(yōu)化、網(wǎng)站收錄、、網(wǎng)站營銷、響應(yīng)式網(wǎng)站
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來源: 創(chuàng)新互聯(lián)