javascript----閉包

閉包是什么

對(duì)于這個(gè)問題,我只能給你淫一句詩:

" 不識(shí)廬山真面目,只緣身在此山中 "

閉包的使用在我們的平時(shí)代碼的書寫和使用中太常見了,我舉幾個(gè)栗子給你瞧瞧!
function foo(){ var name = "LiAo"; function bar(){ console.log(name); } return bar; } var baz = foo(); baz(); // "LiAo"
function wait(msg){ setTimeout(function timer(){ console.log(msg); },1000); wait("Hello ,LiAo");
var a = 2 ; (function IIFE(){ console.log(a); })();

這些栗子都使用了閉包,其實(shí)閉包的本質(zhì)是內(nèi)部作用域可以訪問外部作用域的原則续挟,不管內(nèi)部函數(shù)在哪里被調(diào)用钮孵,它都能夠訪問到外部函數(shù)的作用域

關(guān)于閉包的經(jīng)典問題

for(var i=1;i<=5;i++){ setTimeout(function timer(){ console.log(i); },i*1000); }

這種問題你應(yīng)該看到過很多遍了吧,毫無疑問,運(yùn)行時(shí)會(huì)以每秒一次的頻率輸出五次6(等setTimeout里面的函數(shù)開始運(yùn)行時(shí),for循環(huán)早已完成,i早已置為6,而此時(shí)每個(gè)回調(diào)函數(shù)都在引用完成時(shí)候的變量i,自然都是輸出6),
為了達(dá)到預(yù)期的效果禽篱,有很多種辦法
for(var i=1;i<=5;i++){ (function(){ var j = i; setTimeout(function timer(){ console.log(j); },j*1000); })() }
通過一個(gè)IIFE來創(chuàng)建作用域,此時(shí)每個(gè)循環(huán)都有一個(gè)塊級(jí)作用域馍惹,由最初的共享i變成分別訪問自己塊級(jí)作用域的j躺率,而這個(gè)j又保存著執(zhí)行循環(huán)時(shí)候i的值,從而得到了正確的結(jié)果
for(var i=1;i<=5;i++){ (function(j){ var j = i; setTimeout(function timer(){ console.log(j); },j*1000); })(i) }
其實(shí)這種方法跟上面那種是一樣的道理万矾,只不過這里采用隱式賦值悼吱,還記得嗎,js函數(shù)的參數(shù)是按值傳遞的良狈,因?yàn)閷傳給立即執(zhí)行函數(shù)后添,相當(dāng)于執(zhí)行了var j =i;從而保存了到時(shí)的i值们颜,得到了正確的結(jié)果吕朵。
for(var i=1;i<=5;i++){ let j=i; setTimeout(function timer(){ console.log(j); },j*1000); }
這種方法使用了ES6的let標(biāo)識(shí)符,let標(biāo)識(shí)符讓所在代碼塊能獨(dú)立成為一個(gè)作用域窥突,因而保存了正確的值。
上面的方法也可以簡化為下面的形式
for(let i=1;i<=5;i++){ setTimeout(function timer(){ console.log(i); },i*1000); }

var name = "The Window"; var object = { name:"My Object", getNameFunc:function(){ return function(){ return this.name; }; } }; alert(object.getNameFunc()()); //"The Window"
這個(gè)問題是匿名函數(shù)并沒有渠道其包含作用域的this對(duì)象
因?yàn)槊總€(gè)函數(shù)在被調(diào)用時(shí)候都會(huì)自動(dòng)取得兩個(gè)特殊變量:this和arguments硫嘶,這兩個(gè)變量在函數(shù)被調(diào)用時(shí)動(dòng)態(tài)綁定阻问。內(nèi)部函數(shù)在搜索這兩個(gè)變量時(shí),只會(huì)搜索到其活動(dòng)對(duì)象為止沦疾,因此永遠(yuǎn)不能直接訪問到外部函數(shù)中的這兩個(gè)變量称近。
解決方案
var object = { name:"My Object", getNameFunc:function(){ var that = this; return function(){ return that.name; } } }

內(nèi)存泄漏問題
function assignHandler(){ var element = document.getElementById("someElement"); element.onclick = function(){ alert(element.id); } }
在這里我們只需要獲得元素的id值即可,而elment.id直接引用了元素本身哮塞,導(dǎo)致這元素?zé)o法被銷毀刨秆,堆積多了,自然會(huì)導(dǎo)致性能下降
解決方案
function assignHandler(){ var element = document.getElementById("someElement"); var id =element.id; element.onclick = function(){ alert(id); } element = null; }
這里我們只需要保存元素的值就行忆畅,不用引用該元素衡未,另外,即使閉包不直接引用element家凯,包含函數(shù)的活動(dòng)對(duì)象也會(huì)仍然保存一個(gè)引用缓醋,所以有必要把element變量設(shè)置為null。

閉包的使用

模仿塊級(jí)作用域

(function(){ //這里是塊級(jí)作用域绊诲; })();

私有變量

function MyOject(){ var privateVariable = 10; function privateFunction(){ return false; } this.publicMethod = function(){ privateVariable++; return privateFunction(); } }
優(yōu)點(diǎn): 每個(gè)實(shí)例都有自己的私有變量和方法
缺點(diǎn):針對(duì)每個(gè)實(shí)例都會(huì)無必要的創(chuàng)建同一組新方法送粱。

靜態(tài)私有變量

function(){ var money = 10; Couple = function(name,age){ this.name = name; this.age = age; }; Couple.prototype.getMoney = function(){ console.log("You have "+money+" money at all") return money; } Couple.prototype.storage = function(num){ money += num; console.log("storage success and you only have "+ money+" at all") } Couple.prototype.draw = function(num){ if(money>=num){ money -= num; console.log("draw success and you only have "+ money+" at all") }else{ console.log("Error! You haven't enough money and the money only remains "+money) } } })(); var LiAo = new Couple("LiAo",22); var Lan = new Couple("Lan",21); LiAo.getMoney(); Lan.getMoney(); LiAo.storage(1000); Lan.draw(500); LiAo.getMoney(); Lan.getMoney(); LiAo.draw(300); Lan.draw(800); You have 10 money at all You have 10 money at all storage success and you only have 1010 at all draw success and you only have 510 at all You have 510 money at all You have 510 money at all draw success and you only have 210 at all
這里是我想到的一種應(yīng)用場(chǎng)景:夫妻共同使用一個(gè)銀行賬戶,固然存款是私有的掂之,不能被直接訪問的變量抗俄,但是夫妻都有方法進(jìn)行存和取錢脆丁。兩者的存取都會(huì)影響到他們共同的存款即私有變量,靜態(tài)私有變量例子的每個(gè)實(shí)例都是共享同一個(gè)私有變量的动雹,所以適合用于多個(gè)實(shí)例共同使用一個(gè)變量的情況偎快。而前面的私有變量例子是每個(gè)實(shí)例都有自己的私有變量,互不影響洽胶。

模塊模式

模塊模式是為單例創(chuàng)建私有變量和特權(quán)方法,而在javascript中是以對(duì)象字面量的方式來創(chuàng)建單例對(duì)象的
var singleton = function(){ var privateVariable = 10; function privateFunction(){ return false; } return { publicProperty:true, publicMethod:function(){ privateVariable++; return privateFunction(); } }; }();
這種模式在需要對(duì)單例進(jìn)行某些初始化,同時(shí)又需要維護(hù)其私有變量時(shí)是非常有用的.

增強(qiáng)的模塊模式

增強(qiáng)的模塊模式適合那些單例必須是某種類型的實(shí)例,同時(shí)還必須添加某些屬性和(或)方法對(duì)其加以增強(qiáng)的情況
如:
var singleton = function(){ var privateVariable = 10; function privateFunction(){ return false; } var object = new CustomType(); object.publicMethod = function(){ privateVariable++; return privateFunction(); } return object; }();

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末晒夹,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子姊氓,更是在濱河造成了極大的恐慌丐怯,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,039評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件翔横,死亡現(xiàn)場(chǎng)離奇詭異读跷,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)禾唁,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,426評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門效览,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人荡短,你說我怎么就攤上這事丐枉。” “怎么了掘托?”我有些...
    開封第一講書人閱讀 165,417評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵瘦锹,是天一觀的道長。 經(jīng)常有香客問我闪盔,道長弯院,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,868評(píng)論 1 295
  • 正文 為了忘掉前任泪掀,我火速辦了婚禮听绳,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘异赫。我一直安慰自己椅挣,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,892評(píng)論 6 392
  • 文/花漫 我一把揭開白布祝辣。 她就那樣靜靜地躺著贴妻,像睡著了一般。 火紅的嫁衣襯著肌膚如雪蝙斜。 梳的紋絲不亂的頭發(fā)上名惩,一...
    開封第一講書人閱讀 51,692評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音孕荠,去河邊找鬼娩鹉。 笑死攻谁,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的弯予。 我是一名探鬼主播戚宦,決...
    沈念sama閱讀 40,416評(píng)論 3 419
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼锈嫩!你這毒婦竟也來了受楼?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,326評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤呼寸,失蹤者是張志新(化名)和其女友劉穎艳汽,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體对雪,經(jīng)...
    沈念sama閱讀 45,782評(píng)論 1 316
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡河狐,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,957評(píng)論 3 337
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了瑟捣。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片馋艺。...
    茶點(diǎn)故事閱讀 40,102評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖迈套,靈堂內(nèi)的尸體忽然破棺而出捐祠,到底是詐尸還是另有隱情,我是刑警寧澤交汤,帶...
    沈念sama閱讀 35,790評(píng)論 5 346
  • 正文 年R本政府宣布雏赦,位于F島的核電站,受9級(jí)特大地震影響芙扎,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜填大,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,442評(píng)論 3 331
  • 文/蒙蒙 一戒洼、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧允华,春花似錦圈浇、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,996評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至百炬,卻和暖如春褐隆,著一層夾襖步出監(jiān)牢的瞬間剖踊,已是汗流浹背庶弃。 一陣腳步聲響...
    開封第一講書人閱讀 33,113評(píng)論 1 272
  • 我被黑心中介騙來泰國打工衫贬, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人歇攻。 一個(gè)月前我還...
    沈念sama閱讀 48,332評(píng)論 3 373
  • 正文 我出身青樓固惯,卻偏偏與公主長得像,于是被迫代替她去往敵國和親缴守。 傳聞我的和親對(duì)象是個(gè)殘疾皇子葬毫,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,044評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容

  • 前言 總括 :這篇文章使用有效的javascript代碼向程序員們解釋了閉包,大牛和功能型程序員請(qǐng)自行忽略屡穗。 譯者...
    KX九五閱讀 278評(píng)論 0 1
  • 一贴捡、閉包有什么用 1、能夠在函數(shù)外部引用函數(shù)內(nèi)部的變量(變量作用域)鸡捐; 2栈暇、讓變量的值始終保持在內(nèi)存中(垃圾回收機(jī)...
    你這個(gè)人真的是閱讀 357評(píng)論 0 1
  • 什么是閉包? 有什么作用 閉包是指一個(gè)函數(shù)可以調(diào)用其他函數(shù)的變量。最常見的閉包就是一個(gè)函數(shù)嵌套另一個(gè)函數(shù)箍镜; 閉包的...
    尹薩薩閱讀 324評(píng)論 0 0
  • 工廠模式類似于現(xiàn)實(shí)生活中的工廠可以產(chǎn)生大量相似的商品源祈,去做同樣的事情,實(shí)現(xiàn)同樣的效果;這時(shí)候需要使用工廠模式色迂。簡單...
    舟漁行舟閱讀 7,769評(píng)論 2 17
  • 寒假放假在家香缺,與長久不見的閨蜜小聚,逛吃逛吃歇僧,最后图张,竟不想回家了,于是找了個(gè)賓館暢談人生理想诈悍。 早上九點(diǎn)多被一通電...
    ThinkingTOMATO閱讀 765評(píng)論 1 1