怎樣理解JavaScript 閉包,相信很多沒有經(jīng)驗(yàn)的人對(duì)此束手無(wú)策,為此本文總結(jié)了問(wèn)題出現(xiàn)的原因和解決方法,通過(guò)這篇文章希望你能解決這個(gè)問(wèn)題。
公司主營(yíng)業(yè)務(wù):成都做網(wǎng)站、成都網(wǎng)站建設(shè)、成都外貿(mào)網(wǎng)站建設(shè)、移動(dòng)網(wǎng)站開發(fā)等業(yè)務(wù)。幫助企業(yè)客戶真正實(shí)現(xiàn)互聯(lián)網(wǎng)宣傳,提高企業(yè)的競(jìng)爭(zhēng)能力。成都創(chuàng)新互聯(lián)公司是一支青春激揚(yáng)、勤奮敬業(yè)、活力青春激揚(yáng)、勤奮敬業(yè)、活力澎湃、和諧高效的團(tuán)隊(duì)。公司秉承以“開放、自由、嚴(yán)謹(jǐn)、自律”為核心的企業(yè)文化,感謝他們對(duì)我們的高要求,感謝他們從不同領(lǐng)域給我們帶來(lái)的挑戰(zhàn),讓我們激情的團(tuán)隊(duì)有機(jī)會(huì)用頭腦與智慧不斷的給客戶帶來(lái)驚喜。成都創(chuàng)新互聯(lián)公司推出蘭州免費(fèi)做網(wǎng)站回饋大家。
深入剖析 JavaScript 閉包
?一個(gè)函數(shù)和對(duì)其周圍狀態(tài)的引用捆綁在一起,這樣的組合就是「閉包」.
通俗的說(shuō):一個(gè)內(nèi)層函數(shù)可以訪問(wèn)外層函數(shù)的作用域 就叫 「閉包」。
在 JavaScript 中,每當(dāng)創(chuàng)建一個(gè)函數(shù),閉包就會(huì)在函數(shù)創(chuàng)建的同時(shí)被創(chuàng)建出來(lái)。
閉包的形成與變量的作用域以及變量的生命周期密切相關(guān)。
?
??
函數(shù)嵌套函數(shù)
函數(shù)內(nèi)部可以引用外部的參數(shù)和變量
參數(shù)和變量不會(huì)被垃圾回收機(jī)制回收
?優(yōu)點(diǎn):
?可以設(shè)計(jì)私有的方法和變量
?「缺點(diǎn)」
?常駐內(nèi)存,會(huì)增大內(nèi)存使用量,使用不當(dāng)很容易造成內(nèi)存泄露。
?「一般函數(shù)執(zhí)行完畢后,局部活動(dòng)對(duì)象就被銷毀,內(nèi)存中僅僅保存全局作用域?!?/strong>
?
?變量的作用域:變量的有效范圍。
在實(shí)際開發(fā)中,我們經(jīng)常遇到的是 「函數(shù)中聲明的變量作用域?!?/strong>
?
var a = '閉包';
function getValue(){
var a = '函數(shù)局部作用域'
console.log(a)
}
getValue() //函數(shù)局部作用域
?當(dāng)在全局聲明了一個(gè)同名變量,在函數(shù)內(nèi)部也聲明了一個(gè)同名變量,函數(shù)優(yōu)先訪問(wèn)函數(shù)作用域中的變量。
?
?函數(shù)作用域:在函數(shù)內(nèi)部可以訪問(wèn)到函數(shù)外部變量,而在函數(shù)外部的變量不可以訪問(wèn)函數(shù)內(nèi)部的變量。
為什么呢?
「因?yàn)楫?dāng)在函數(shù)中搜索一個(gè)變量的時(shí)候,如果函數(shù)內(nèi)部沒有這個(gè)變量的聲明,那么它會(huì)隨著代碼的執(zhí)行環(huán)境創(chuàng)建的作用域往外層逐層搜索,直到搜索到全局變量為止。」
變量的搜索是從內(nèi)到外搜索的。
?
function getData() {
var str = "閉包練習(xí)";
var fun = function(){
var innerStr = '內(nèi)部變量'
}
console.log(innerStr)
//innerStr is not defined 函數(shù)外層是訪問(wèn)不到 函數(shù)內(nèi)層變量的
}
getData()
?對(duì)于 「全局變量」,它的生存周期是永久的的,除非主動(dòng)銷毀變量。
而對(duì)于 「函數(shù)局部變量」,當(dāng)函數(shù)執(zhí)行完畢,局部變量也就銷毀了。
?
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div>1</div>
<div>2</div>
<div>3</div>
<div>4</div>
<script>
var nodes = document.getElementsByTagName('div')
for (var i = 0; i < nodes.length; i++) {
nodes[i].onclick = function () {
alert(i)
}
}
</script>
</body>
</html>
?給每個(gè)
div
增加點(diǎn)擊事件,當(dāng)點(diǎn)擊 div 時(shí),彈出它對(duì)應(yīng)的索引值。現(xiàn)在無(wú)論點(diǎn)擊哪個(gè)
div
,它 彈出的 都是 4 。為什么呢?
「因?yàn)?div 點(diǎn)擊事件 是被 異步觸發(fā)的,當(dāng)事件被觸發(fā)的時(shí)候,循環(huán)已經(jīng)執(zhí)行完,此時(shí)的 i 的 變量值 為 4?!?/strong>
如何解決 點(diǎn)擊每個(gè)div 彈出對(duì)應(yīng)的i 值呢 ?
**可以借用 閉包, 把每次循環(huán)的 i 保存起來(lái),當(dāng)執(zhí)行點(diǎn)擊事件時(shí),它會(huì)從內(nèi)到外 搜索變量的作用域,它會(huì)優(yōu)先搜索到 閉包環(huán)境環(huán)境的 i **
?
# 閉包解決辦法
<script>
var nodes = document.getElementsByTagName('div')
for (var i = 0; i < nodes.length; i++) {
(function(i) {
nodes[i].onclick = function () {
alert(i)
}
})(i)
}
</script>
var num = 1;
function getValue(){
var num = 0;
return function(){
num++
console.log(num)
}
}
var s = getValue()
s()
s()
// 1 2
?按常理思路來(lái):函數(shù)執(zhí)行完畢,num = 1 銷毀,變?yōu)槌跏贾?num = 0 ,變量在函數(shù)中作用域從內(nèi)到外逐層搜索。
前面也說(shuō)到了,當(dāng)函數(shù)執(zhí)行完,局部變量也跟著銷毀了,那為什么會(huì) 輸出 2 呢 ?
?這里 涉及到 垃圾回收機(jī)制引用計(jì)數(shù)問(wèn)題
[關(guān)于垃圾回收] https://blog.csdn.net/zhouziyu2011/article/details/61201613
簡(jiǎn)述:
「當(dāng)聲明了一個(gè)變量并將一個(gè)引用類型值賦給該變量時(shí),則該值的引用次數(shù)就是1;如果同一個(gè)值又被賦給另一個(gè)變量,則該值的引用次數(shù)加1;如果包含對(duì)該值引用的變量又取得了另外一個(gè)值,則該值的引用次數(shù)減1。當(dāng)該值的引用次數(shù)變?yōu)?時(shí),則可以回收其占用的內(nèi)存空間。當(dāng)垃圾回收器下一次運(yùn)行時(shí),就會(huì)釋放那些引用次數(shù)為0的值所占用的內(nèi)存?!?/strong>
?「解答」
?第一次執(zhí)行
s()
時(shí),num = 1第二次 執(zhí)行
?s()
時(shí), 由于 引用的時(shí)第一次s ()
的變量num=1,num 沒有被銷毀,固然在 num = 1 的基礎(chǔ)上 再 加 1 。「注意」
如果沒有使用同樣引用的話,那么多次調(diào)用,都是同樣的值,因?yàn)闆]有記錄引用值。
函數(shù)在執(zhí)行完畢,num = 1 被銷毀掉了,初始為 0
?
var num = 1;
function getValue(){
var num = 0;
return function(){
num++
console.log(num)
}
}
getValue()()
getValue()()
// 0 0
?閉包的注意作用為這兩項(xiàng):
?
「可以讀取函數(shù)內(nèi)部的變量」 「可以變量的值始終保持在內(nèi)存中」
function f2(){
let num = 0;
addNum = function(){
num++
}
function f3(){
console.log(num)
}
return f3
}
var a = f2()
a()
addNum()
a()
// 0 1
?閉包注意
結(jié)果為 0 1
函數(shù)在執(zhí)行完畢,局部變量也跟著銷毀, 結(jié)果 不應(yīng)該是 0 0 嗎 ?
其實(shí)a() 相當(dāng)于 是 f3() 的閉包函數(shù),它被執(zhí)行了兩次。
第一次 執(zhí)行 a() 時(shí), 結(jié)果為 0 , 很好理解。 第二次 執(zhí)行的 f2()
函數(shù)內(nèi)部的addNum
函數(shù),發(fā)現(xiàn)沒這個(gè)匿名函數(shù)賦值給一個(gè)變量,而且這個(gè)變量沒加var / let
, 那么它此時(shí)的作用域?yàn)?全局
,保存在內(nèi)存當(dāng)中。執(zhí)行addNum
時(shí)它訪問(wèn)的f2()
函數(shù)內(nèi)部的局部變量num
, 此時(shí),addNum
的存在依賴于f2
,因此f2
也在內(nèi)存中,不會(huì)在調(diào)用結(jié)束后,被垃圾回收機(jī)制(garbage collection)回收。第三次 執(zhí)行 a()
時(shí), 因?yàn)?num
已存在內(nèi)存中,而 值為1最終輸出結(jié)果:0 , 1
?
?
由于閉包會(huì)使得函數(shù)中的變量都被保存在內(nèi)存中,內(nèi)存消耗很大,所以不能濫用閉包,否則會(huì)造成網(wǎng)頁(yè)的性能問(wèn)題,在IE中可能導(dǎo)致內(nèi)存泄露。解決方法是,在退出函數(shù)之前,將不使用的局部變量全部刪除。 閉包會(huì)在父函數(shù)外部,改變父函數(shù)內(nèi)部變量的值。所以,如果你把父函數(shù)當(dāng)作對(duì)象(object)使用,把閉包當(dāng)作它的公用方法(Public Method),把內(nèi)部變量當(dāng)作它的私有屬性(private value),這時(shí)一定要小心,不要隨便改變父函數(shù)內(nèi)部變量的值。
看完上述內(nèi)容,你們掌握怎樣理解JavaScript 閉包的方法了嗎?如果還想學(xué)到更多技能或想了解更多相關(guān)內(nèi)容,歡迎關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道,感謝各位的閱讀!
分享標(biāo)題:怎樣理解JavaScript閉包
網(wǎng)頁(yè)路徑:http://chinadenli.net/article8/gjshop.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供品牌網(wǎng)站建設(shè)、域名注冊(cè)、品牌網(wǎng)站制作、小程序開發(fā)、建站公司、外貿(mào)建站
聲明:本網(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í)需注明來(lái)源: 創(chuàng)新互聯(lián)