Javascript 中一個(gè)最重要的特性就是閉包的使用。因?yàn)殚]包的使用,當(dāng)前作用域總可以訪問(wèn)外部的作用域。因?yàn)?Javascript 沒(méi)有塊級(jí)作用域,只有函數(shù)作用域,所以閉包的使用與函數(shù)是緊密相關(guān)的。
模擬私有變量function Counter(start) { var count = start; return { increment: function() { count++; }, get: function() { return count; } } } var foo = Counter(4); foo.increment(); foo.get(); // 5
這里 Counter 返回兩個(gè)閉包:函數(shù) increment 和 get。這兩個(gè)函數(shù)一直保持著對(duì) Counter 作用域的訪問(wèn),因此它們能一直訪問(wèn)到定義在 Counter 作用域的變量 count。
私有變量的工作機(jī)制由于 Javascript 不可以對(duì)作用域賦值和引用,所以在上例中,是沒(méi)有辦法在外部直接訪問(wèn)內(nèi)部私有變量 count。唯一的方法就是通過(guò)定義閉包來(lái)訪問(wèn)。
var foo = new Counter(4); foo.hack = function() { count = 1337; };
上面的代碼不會(huì)改變 Counter 作用域內(nèi)的 count 變量值,因?yàn)?hack 沒(méi)有在 Counter 內(nèi)定義。上面這段代碼只會(huì)創(chuàng)建或者覆蓋全局變量 count。
循環(huán)內(nèi)的閉包一個(gè)最容易犯的錯(cuò)誤就是在循環(huán)內(nèi)使用閉包。
for(var i = 0; i < 10; i++) { setTimeout(function() { console.log(i); }, 1000); }
上面這段代碼不會(huì)輸出0到9,而是連續(xù)輸出10次10。
上面的匿名會(huì)一直保持一個(gè)對(duì)變量 i 的引用。當(dāng)調(diào)用 console.log 函數(shù)開(kāi)始輸出時(shí),這是循環(huán)已經(jīng)結(jié)束,而變量 i 已經(jīng)為10了。
為了避免上面的錯(cuò)誤發(fā)生,我們需要在每次循環(huán)時(shí)為變量 i 值創(chuàng)建一個(gè)拷貝。
為了復(fù)制循環(huán)中變量的值,最好的方式是在外層加一個(gè)匿名的立刻執(zhí)行函數(shù)。
for(var i = 0; i < 10; i++) { (function(e) { setTimeout(function() { console.log(e); }, 1000); })(i); }
這個(gè)外部的匿名函數(shù)接收循環(huán)變量 i 作為第一個(gè)參數(shù),并將其值拷貝至它自身的參數(shù) e。
外部的匿名函數(shù)將參數(shù) e 再傳遞給 setTimeout,因此 setTimeout 有了指向參數(shù) e 的引用。而且這個(gè)參數(shù) e 的值不會(huì)因?yàn)橥獠康难h(huán)改變而改變。
這里涉及到了立即執(zhí)行函數(shù),它的具體含義可以參考這個(gè)回答:
http://segmentfault.com/q/1010000000442042#a-1020000000442404
還有另外一個(gè)方法可以實(shí)現(xiàn)同樣的效果,就是在 setTimeout 內(nèi)的匿名函數(shù)中再返回一個(gè)匿名函數(shù):
for(var i = 0; i < 10; i++) { setTimeout((function(e) { return function() { console.log(e); } })(i), 1000) }
此外,通過(guò) bind 方法也可以實(shí)現(xiàn)。
for(var i = 0; i < 10; i++) { setTimeout(console.log.bind(console, i), 1000); }參考
http://bonsaiden.github.io/JavaScript-Garden/#function.closures
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/87517.html
Javascript 中的構(gòu)造函數(shù)與其他語(yǔ)言相比也是不同的。任何通過(guò)關(guān)鍵字 new 調(diào)用的函數(shù)都可以當(dāng)做構(gòu)造函數(shù)。 在構(gòu)造函數(shù)體內(nèi),this 指向新創(chuàng)建的對(duì)象。如果構(gòu)造函數(shù)體內(nèi)沒(méi)有顯示的 return 表達(dá)式,那么我們就默認(rèn)返回 this,也就是新建的對(duì)象。 function Foo() { this.bla = 1; } Foo.prototype.test = function()...
摘要:并沒(méi)有類(lèi)繼承模型,而是使用原型對(duì)象進(jìn)行原型式繼承。我們舉例說(shuō)明原型鏈查找機(jī)制當(dāng)訪問(wèn)一個(gè)對(duì)象的屬性時(shí),會(huì)從對(duì)象本身開(kāi)始往上遍歷整個(gè)原型鏈,直到找到對(duì)應(yīng)屬性為止。原始類(lèi)型有以下五種型。此外,試圖查找一個(gè)不存在屬性時(shí)將會(huì)遍歷整個(gè)原型鏈。 Javascript 并沒(méi)有類(lèi)繼承模型,而是使用原型對(duì)象 prototype 進(jìn)行原型式繼承。 盡管人們經(jīng)常將此看做是 Javascript 的一個(gè)缺點(diǎn),然...
摘要:閉包執(zhí)行上下文決定了變量作用域而閉包,它其實(shí)是一種決策,是一種模式,讓我們可以靈活的改變變量作用域。所以,在本質(zhì)上,閉包就是將函數(shù)內(nèi)部和函數(shù)外部連接起來(lái)的一座橋梁。只要咱們弄明白閉包,其中的自然跑不掉。 閉包 this 執(zhí)行上下文決定了變量作用域 而閉包,它其實(shí)是一種決策,是一種模式,讓我們可以靈活的改變變量作用域。 按慣例,上栗子 var global = glo...
摘要:的操作符可以用來(lái)比較兩個(gè)操作數(shù)的構(gòu)造函數(shù)。這是因?yàn)樗鼈兊臉?gòu)造函數(shù)不可能會(huì)是同一個(gè)對(duì)象。總結(jié)綜上所述,我們知道操作符最合適的使用壞境是比較兩個(gè)相同上下文背景下的自定義對(duì)象的構(gòu)造函數(shù),正如上篇介紹的操作符,其他壞境下使用作用不大。 Javascript 的 instanceof 操作符可以用來(lái)比較兩個(gè)操作數(shù)的構(gòu)造函數(shù) constructor。但這個(gè)只有在比較自定義對(duì)象才有意義。當(dāng)用來(lái)比較 ...
摘要:在元素一篇介紹過(guò),可以使用來(lái)使得代碼在加載完畢后自動(dòng)執(zhí)行代碼,接下來(lái)具體介紹下這個(gè)機(jī)制。這樣看上去貌似沒(méi)什么問(wèn)題,但是如果有兩個(gè)函數(shù)需要指定時(shí)就會(huì)遇到麻煩,因?yàn)閷傩灾荒鼙4鎸?duì)一個(gè)函數(shù)的引用,如果我們寫(xiě)成以下形式最后代碼執(zhí)行后的效果是會(huì)覆蓋。 在元素一篇介紹過(guò),jQuery 可以使用 $(document).ready() 來(lái)使得代碼在 DOM 加載完畢后自動(dòng)執(zhí)行代碼,接下來(lái)具體介紹下這...
閱讀 485·2023-04-25 17:26
閱讀 1504·2021-08-05 09:58
閱讀 1970·2019-08-30 13:17
閱讀 953·2019-08-28 17:52
閱讀 1069·2019-08-26 18:27
閱讀 1424·2019-08-26 14:05
閱讀 3622·2019-08-26 14:05
閱讀 1597·2019-08-26 10:45