天天躁日日躁狠狠躁AV麻豆-天天躁人人躁人人躁狂躁-天天澡夜夜澡人人澡-天天影视香色欲综合网-国产成人女人在线视频观看-国产成人女人视频在线观看

前端開發(fā)必須知道的JS之閉包及應(yīng)用

在前端開發(fā)必須知道的JS之原型和繼承一文中說過下面寫篇閉包,加之最近越來越發(fā)現(xiàn)需要加強(qiáng)我的閉包應(yīng)用能力,所以此文不能再拖了。本文講的是函數(shù)閉包,不涉及對(duì)象閉包(如用with實(shí)現(xiàn))。如果你覺得我說的有偏差,歡迎拍磚,歡迎指教。
一. 閉包的理論
  首先必須了解以下幾個(gè)概念:

  執(zhí)行環(huán)境
  每調(diào)用一個(gè)函數(shù)時(shí)(執(zhí)行函數(shù)時(shí)),系統(tǒng)會(huì)為該函數(shù)創(chuàng)建一個(gè)封閉的局部的運(yùn)行環(huán)境,即該函數(shù)的執(zhí)行環(huán)境。函數(shù)總是在自己的執(zhí)行環(huán)境中執(zhí)行,如讀寫局部變量、函數(shù)參數(shù)、運(yùn)行內(nèi)部邏輯。創(chuàng)建執(zhí)行環(huán)境的過程包含了創(chuàng)建函數(shù)的作用域,函數(shù)也是在自己的作用域下執(zhí)行的。從另一個(gè)角度說,每個(gè)函數(shù)執(zhí)行環(huán)境都有一個(gè)作用域鏈,子函數(shù)的作用域鏈包括它的父函數(shù)的作用域鏈。關(guān)于作用域、作用域鏈請(qǐng)看下面。

  作用域、作用域鏈、調(diào)用對(duì)象
  函數(shù)作用域分為詞法作用域和動(dòng)態(tài)作用域。
  詞法作用域是函數(shù)定義時(shí)的作用域,即靜態(tài)作用域。當(dāng)一個(gè)函數(shù)定義時(shí),他的詞法作用域就確定了,詞法作用域說明的是在函數(shù)結(jié)構(gòu)的嵌套關(guān)系下,函數(shù)作用的范圍。這個(gè)時(shí)候也就形成了該函數(shù)的作用域鏈。作用域鏈就是把這些具有嵌套層級(jí)關(guān)系的作用域串聯(lián)起來。函數(shù)的內(nèi)部[[scope]]屬性指向了該作用域鏈。
  動(dòng)態(tài)作用域是函數(shù)調(diào)用執(zhí)行時(shí)的作用域。當(dāng)一個(gè)函數(shù)被調(diào)用時(shí),首先將函數(shù)內(nèi)部[[scope]]屬性指向了函數(shù)的作用域鏈,然后會(huì)創(chuàng)建一個(gè)調(diào)用對(duì)象,并用該調(diào)用對(duì)象記錄函數(shù)參數(shù)和函數(shù)的局部變量,將其置于作用域鏈頂部。動(dòng)態(tài)作用域就是通過把該調(diào)用對(duì)象加到作用域鏈的頂部來創(chuàng)建的,此時(shí)的[[scope]]除了具有定義時(shí)的作用域鏈,還具有了調(diào)用時(shí)創(chuàng)建的調(diào)用對(duì)象。換句話說,執(zhí)行環(huán)境下的作用域等于該函數(shù)定義時(shí)就確定的作用域鏈加上該函數(shù)剛剛創(chuàng)建的調(diào)用對(duì)象,從而也形成了新的作用域鏈。所以說是動(dòng)態(tài)的作用域,并且作用域鏈也隨之發(fā)生了變化。再看這里的作用域,其實(shí)是一個(gè)對(duì)象鏈,這些對(duì)象就是函數(shù)調(diào)用時(shí)創(chuàng)建的調(diào)用對(duì)象,以及他上面一層層的調(diào)用對(duì)象直到最上層的全局對(duì)象。 
  譬如全局環(huán)境下的函數(shù)A內(nèi)嵌套了一個(gè)函數(shù)B,則該函數(shù)B的作用域鏈就是:函數(shù)B的作用域―>函數(shù)A的作用域―>全局window的作用域。當(dāng)函數(shù)B調(diào)用時(shí),尋找某標(biāo)識(shí)符,會(huì)按函數(shù)B的作用域―>函數(shù)A的作用域―>全局window的作用域去尋找,實(shí)際上是按函數(shù)B的調(diào)用對(duì)象―>函數(shù)A的調(diào)用對(duì)象―>全局對(duì)象這個(gè)順序去尋找的。也就是說當(dāng)函數(shù)調(diào)用時(shí),函數(shù)的作用域鏈實(shí)際上是調(diào)用對(duì)象鏈。

  閉包
  在動(dòng)態(tài)執(zhí)行環(huán)境中,數(shù)據(jù)實(shí)時(shí)地發(fā)生變化,為了保持這些非持久型變量的值,我們用閉包這種載體來存儲(chǔ)這些動(dòng)態(tài)數(shù)據(jù)(看完下面的應(yīng)用就會(huì)很好的體會(huì)這句話)。閉包的定義:所謂“閉包”,指的是一個(gè)擁有許多變量和綁定了這些變量的環(huán)境的表達(dá)式(通常是一個(gè)函數(shù)),因而這些變量也是該表達(dá)式的一部分。
  閉包就是嵌套在函數(shù)里面的內(nèi)部函數(shù),并且該內(nèi)部函數(shù)可以訪問外部函數(shù)中聲明的所有局部變量、參數(shù)和其他內(nèi)部函數(shù)。當(dāng)該內(nèi)部函數(shù)在外部函數(shù)外被調(diào)用,就生成了閉包。(實(shí)際上任何函數(shù)都是全局作用域的內(nèi)部函數(shù),都能訪問全局變量,所以都是window的閉包)
  譬如下面這個(gè)例子:
復(fù)制代碼 代碼如下:
<script type="text/Javascript">
function f(x) {
var a = 0;
a++;
x++;
var inner = function() {
return a + x;
}
return inner;
}
var test = f(1);
alert(test());
</script>

垃圾回收機(jī)制:如果某個(gè)對(duì)象不再被引用,該對(duì)象將被回收。  
  再結(jié)合前面所講的一些概念,在執(zhí)行var test=f(1)時(shí)創(chuàng)建了f的調(diào)用對(duì)象,這里暫且記作obj,執(zhí)行完后雖然退出了外部執(zhí)行環(huán)境,但內(nèi)部函數(shù)inner被外部函數(shù)f外面的一個(gè)變量test引用。由于外部函數(shù)創(chuàng)建的調(diào)用對(duì)象obj有一個(gè)屬性指向此內(nèi)部函數(shù),而現(xiàn)在這個(gè)內(nèi)部函數(shù)又被引用,所以調(diào)用對(duì)象obj會(huì)繼續(xù)存在,不會(huì)被垃圾回收器回收,其函數(shù)參數(shù)x和局部變量a都會(huì)在這個(gè)調(diào)用對(duì)象中得以維持。雖然調(diào)用對(duì)象不能被直接訪問,但是該調(diào)用對(duì)象已成為內(nèi)部函數(shù)作用域鏈中的一部分,可以被內(nèi)部函數(shù)訪問并修改,所以執(zhí)行test()時(shí),可以正確訪問x和a。所以說, 當(dāng)執(zhí)行了外部函數(shù)時(shí),生成了閉包,被引用的外部函數(shù)的變量將繼續(xù)存在。
二. 閉包的應(yīng)用
  應(yīng)用1:
  這個(gè)是我在用js模擬排序算法過程遇到的問題。我要輸出每一次插入排序后的數(shù)組,如果在循環(huán)中寫成
  setTimeout(function() { $("proc").innerHTML += arr + "<br/>"; }, i * 500);
會(huì)發(fā)現(xiàn)每次輸出的都是最終排好序的數(shù)組,因?yàn)閍rr數(shù)組不會(huì)為你保留每次排序的狀態(tài)值。為了保存會(huì)不斷發(fā)生變化的數(shù)組值,我們用外面包裹一層函數(shù)來實(shí)現(xiàn)閉包,用閉包存儲(chǔ)這個(gè)動(dòng)態(tài)數(shù)據(jù)。下面用了2種方式實(shí)現(xiàn)閉包,一種是用參數(shù)存儲(chǔ)數(shù)組的值,一種是用臨時(shí)變量存儲(chǔ),后者必須要深拷貝。所有要通過閉包存儲(chǔ)非持久型變量,均可以用臨時(shí)變量或參數(shù)兩種方式實(shí)現(xiàn)。

[Ctrl+A 全選 注:如需引入外部Js需刷新才能執(zhí)行]
應(yīng)用2:
  這個(gè)是無憂上的例子(點(diǎn)擊這里查看原帖),為每個(gè)<li>結(jié)點(diǎn)綁定click事件彈出循環(huán)的索引值。起初寫成
id.onclick = function(){ alert(i); }  id.onclick = function(){alert(i);}
發(fā)現(xiàn)最終彈出的都是4,而不是想要的 1、2、3,因?yàn)檠h(huán)完畢后i值變成了4。為了保存i的值,同樣我們用閉包實(shí)現(xiàn):

[Ctrl+A 全選 注:如需引入外部Js需刷新才能執(zhí)行]
(ps:var a = (function(){})(); 與 var a =new function(){}效果是一樣的,均表示自執(zhí)行函數(shù)。)
  應(yīng)用3:
  下面的code是緩存的應(yīng)用,catchNameArr。在匿名函數(shù)的調(diào)用對(duì)象中保存catch的值,返回的對(duì)象由于被CachedBox變量引用導(dǎo)致匿名函數(shù)的調(diào)用對(duì)象不會(huì)被回收,從而保持了catch的值。可以通過CachedBox.getCatch("regionId");來操作,若找不到regionId則從后臺(tái)取,catchNameArr 主要是為了防止緩存過大。
復(fù)制代碼 代碼如下:
<script type="text/Javascript">
var CachedBox = (function() {
var cache = {}, catchNameArr = [], catchMax = 10000;
return {
getCatch: function(name) {
if (name in cache) {
return cache[name];
}
var value = GetDataFromBackend();
cache[name] = value;
catchNameArr.push(name);
this.clearOldCatch();
return value;
},
clearOldCatch: function() {
if (catchNameArr.length > catchMax) {
delete cache[catchNameArr.shift()];
}
}
};
})();
</script>

同理,也可以用這種思想實(shí)現(xiàn)自增長(zhǎng)的ID。  
復(fù)制代碼 代碼如下:
<script type="text/Javascript">
var GetId = (function() {
var id = 0;
return function() {
return id++;
}
})();
var newId1 = GetId();
var newId2 = GetId();
</script>

應(yīng)用4:
  這個(gè)是無憂上月MM的例子(點(diǎn)擊這里查看原帖),用閉包實(shí)現(xiàn)程序的暫停執(zhí)行功能,還蠻創(chuàng)意的。

[Ctrl+A 全選 注:如需引入外部Js需刷新才能執(zhí)行]
把這個(gè)作用延伸下,我想到了用他來實(shí)現(xiàn)window.confirm。

[Ctrl+A 全選 注:如需引入外部Js需刷新才能執(zhí)行]
看了上面的這些應(yīng)用,再回到前面的一句話:在動(dòng)態(tài)執(zhí)行環(huán)境中,數(shù)據(jù)實(shí)時(shí)地發(fā)生變化,為了保持這些非持久型變量的值,我們用閉包這種載體來存儲(chǔ)這些動(dòng)態(tài)數(shù)據(jù)。這就是閉包的作用。也就說遇到需要存儲(chǔ)動(dòng)態(tài)變化的數(shù)據(jù)或?qū)⒈换厥盏臄?shù)據(jù)時(shí),我們可以通過外面再包裹一層函數(shù)形成閉包來解決。
  當(dāng)然,閉包會(huì)導(dǎo)致很多外部函數(shù)的調(diào)用對(duì)象不能釋放,濫用閉包會(huì)使得內(nèi)存泄露,所以在頻繁生成閉包的情景下我們要估計(jì)下他帶來的副作用。
  畢了。希望能對(duì)大家有所幫助。
者:JayChow
出處:http://ljchow.cnblogs.com

JavaScript技術(shù)前端開發(fā)必須知道的JS之閉包及應(yīng)用,轉(zhuǎn)載需保留來源!

鄭重聲明:本文版權(quán)歸原作者所有,轉(zhuǎn)載文章僅為傳播更多信息之目的,如作者信息標(biāo)記有誤,請(qǐng)第一時(shí)間聯(lián)系我們修改或刪除,多謝。

主站蜘蛛池模板: 果冻传媒2021在线观看 | 国产成人免费片在线视频观看 | 日本理论片和搜子同居的日子2 | 最懂男人心论坛 | 精品九九视频 | 亚洲午夜福利未满十八勿进 | 亚洲爆乳无码精品AAA片蜜桃 | 亚洲第一成年人网站 | 亚洲 无码 在线 专区 | 国产一区二区三区乱码在线观看 | 日本中文字幕巨大的乳专区 | 果冻传媒2021精品在线观看 | 爆操大胸美女 | 日本久久久WWW成人免费毛片丨 | 亚洲国产高清在线观看视频 | 妈妈的职业3完整版在线播放 | 亚洲色噜噜狠狠网站 | 亚洲人美女肛交真人全程 | 国产精品人妻久久无码不卡 | 久久全国免费观看视频 | 久久精品国产亚洲AV蜜臀 | 最近中文字幕完整版高清 | 校草让我脱了内裤给全班看 | 影音先锋色av男人资源网 | 久久久精品久久 | 99热这里只有 精品 99热这里只就有精品22 | 亚洲 日韩 国产 制服 在线 | 成人免费毛片观看 | 高清国产免费观看视频在线 | 第七色男人天堂 | 广播电台在线收听 | 久久综合香蕉久久久久久久 | 午夜伦理电影在线观免费 | 香蕉久久夜色精品国产小优 | 三叶草成人 | 99视频导航 | 校花被扒衣吸乳羞羞漫画 | 国产区精品综合在线 | 国产精品久久久久无码AV色戒 | 免费人成在线观看视频不卡 | 成人性生交大片免费看金瓶七仙女 |