深入理解JS閉包
關於JS中閉包的理解,相信很多人都和筆者一樣剛開始很是困惑。筆者也是在看了很多前輩的文章後,總結出一點自己的理解。記錄與此,囿於筆者水平有限 ,若有錯誤之處,懇請不嗇賜教。
你可以在一個函式裡面巢狀另外一個函式。巢狀(內部)函式對其容器(外部)函式是私有的。它自身也形成了一個閉包。一個閉包是一個可以自己擁有獨立的環境與變數的的表示式(通常是函式,因為ES6有了塊級作用域的概念)。
https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Guide/Functions(上面這句話摘自這個網址)
第一部分:初遇閉包
http://www.runoob.com/js/js-function-closures.html
什麼是閉包?閉包有什麼作用?這是我遇到閉包時的第一反應。
閉包在JavaScript高階程式設計(第3版)中是這樣描述:閉包是指有權訪問另一個函式作用域中的變數的函式。
那麼閉包的作用也就很明顯了。
1. 可以在函式的外部訪問到函式內部的區域性變數。
2. 讓這些變數始終儲存在記憶體中,不會隨著函式的結束而自動銷燬。
在上面的程式碼中,閉包指的就是function () {return counter += 1;}這個函式。首先解釋一下這段程式碼,在變數add被賦值之前,第一個function執行了一次(執行且僅會執行一次),因為這是一個函式表示式宣告方式並且宣告後加上了(),所以會自動執行一次。執行後add被賦值(匿名函式)了,add= function () {return counter += 1;} 。然後每次呼叫add()函式時,返回的都是這個函式,因為這個函式在第一個函式的內部,所以即使第一個函式執行完了,第二個函式依然能訪問counter(JS設計的作用域鏈,當前作用域能訪問上級的作用域)。
閉包是可以在另一個函式的外部訪問到其作用域中的變數的函式。而被訪問的變數可以和函式一同存在。即使另一個函式已經執行結束,導致建立變數的環境銷燬,也依然會存在,直到訪問變數的那個函式被銷燬。當然,如果僅僅是做一個簡單的計數器,大可不用這樣麻煩。下面這簡短的程式碼就能輕鬆實現。
var a = 0;
function myFunction(){
a++;
document.getElementById("demo").innerHTML = a;
}
推薦一篇部落格:https://blog.csdn.net/qq_36276528/article/details/70049825(寫得很有深度)
第二部分:牛客翻船
https://www.nowcoder.com/questionTerminal/da4115e308c948169a9a73e50d09a3e7
下面是這個題目的解答:
每個li標籤的onclick事件執行時,本身onclick繫結的function的作用域中沒有變數i,i為undefined,則解析引擎會尋找父級作用域,發現父級作用域中有i,且for迴圈繫結事件結束後,i已經賦值為4,所以每個li標籤的onclick事件執行時,alert的都是父作用域中的i,也就是4。這是作用域的問題。
閉包只能取得包含函式中任何變數的最後一個值。因為別忘了閉包所儲存的是整個變數物件,而不是某個特殊的變數。
這是在迴圈體中建立閉包的常見錯誤。https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Closures(一定要看這篇)
這裡面給onclick賦值的是閉包。很多人會問為什麼是閉包?之前閉包不是函式A裡的函式B嗎?函式B用來訪問函式A的變數,稱函式B是閉包,題目中只有一個函式為什麼也是閉包。其實,用兩個函式形成閉包只是一般形式。閉包真正的含義是,如果一個函式訪問了此函式的父級及父級以上的作用域變數,就可以稱這個函式是一個閉包。
<script>
var a = 1;
(function test (){
alert(a);
})()
</script>
所以上面的function都可以稱之為閉包(匿名閉包函式)。
這裡還是作用域的問題,那麼我們把每次的i都儲存到一個變數中,匿名閉包就可以實現想要的效果。
var elements=document.getElementsByTagName('li');
var length=elements.length;
for(var i=0;i<length;i++){
elements[i].onclick=function(num){
return function() {
alert(num);
};
}(i);
}
這樣就使用了閉包,這裡面的閉包指的是function() {alert(num);};第二個function裡面彈出的num是第一個function的引數,通過(i)執行了這裡面的第一個函式,同時i的值被儲存到num中。每個點選事件中都有一個區域性變數num,num儲存的是相應的i值。
第三部分:let的橫空出世
上面的牛客題目只需要將for(var i=0;i<length;i++)中的var改成let就能實現想要的效果,這讓在迴圈體內建立閉包具有更好的可讀性。let的簡單介紹:https://mp.csdn.net/postedit/81065540
let的到來,讓令人詬病的JS獲得了一絲生機,也補上了JS沒有塊級作用域的短板。ECMAScript6還有很多新特性,筆者也在不斷學習中。
第四部分:閉包的應用
函式工廠和閉包模擬私有方法
https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Closures(這篇講得很好,希望讀者們讀透)
相關文章
- 深入理解閉包
- js閉包的理解JS
- 對JS閉包的理解JS
- 深入理解swift的閉包Swift
- JS-閉包(closure)的理解JS
- [譯]理解JS中的閉包JS
- 深入學習js之——閉包#8JS
- 深入理解javascript系列(七):閉包(1)JavaScript
- 深入理解javascript系列(八):閉包(2)JavaScript
- 深入理解javascript系列(九):應用閉包JavaScript
- 理解“閉包”
- 談談我對js中閉包的理解JS
- 深入理解javascript系列(十):模組化與閉包JavaScript
- 理解JavaScript 閉包JavaScript
- Groovy閉包理解
- JS閉包ClosureJS
- JS學習理解之閉包和高階函式JS函式
- PHP 閉包的理解PHP
- 理解Javascript的閉包JavaScript
- 深入學習作用域和閉包—全面(JS系列之二)JS
- Python深入分享之閉包Python
- 深入淺出Javascript閉包JavaScript
- 深入理解執行上下文、作用域鏈和閉包
- 深入理解閉包,裝飾器,深拷貝淺拷貝
- js中的閉包JS
- 淺談js閉包JS
- js函式閉包JS函式
- 理解Python函式閉包Python函式
- 理解 JavaScript 中的閉包JavaScript
- 對javascript閉包的理解JavaScript
- Golang中閉包的理解Golang
- js閉包及閉包的經典使用場景JS
- 簡單理解js閉包、型別引用....第一章JS型別
- 從這兩道題重新理解,JS的this、作用域、閉包、物件JS物件
- JS進擊之路:閉包JS
- JS中的 閉包(Closure)JS
- JS作用域與閉包JS
- JS閉包作用域解析JS