Javascript中有幾個非常重要的語言特性——對象、原型繼承、閉包。其中閉包 對于那些使用傳統靜態語言C/C++的程序員來說是一個新的語言特性。本文將以例子入手來介紹Javascript閉包的語言特性,并結合一點 ECMAScript語言規范來使讀者可以更深入的理解閉包。
很長一段時間不理解閉包,后來了解了作用域,以及this相關問題才理解了閉包相關知識。
閉包(closure),也是面試題常客。簡單點來說就是函數嵌套函數。
函數作為返回值:
- function foo () {
- var a = 1;
- return function () {
- a++;
- console.log(a);
- }
- }
- var aaa = foo();
- aaa(); //2
- aaa(); //3
其實這個代碼不難理解,aaa是指向foo()返回的一個新函數,但是在這個函數里面引用了a變量,所以當執行完foo函數時,變量a還存在內存中不釋放。即a分別為2和3。
函數作為參數:
- var a = 10;
- function foo () {
- console.log(a);
- }
- function aaa(fn) {
- var a = 100;
- fn();
- }
- aaa(foo);
按照我以前的理解,當執行在aaa函數里面執行fn函數,那么如果自身沒有a變量,就去父級作用域找a變量,此處是100,那結果是100嗎?
可惜答案不是,在這里結果是10,王福朋老師的博客講的比較好,他說要去創建這個函數的作用域取值,而不是“父作用域”。
閉包的使用場景
因為本人還比較菜鳥,在這里取一個簡單例子。當點擊li的時候彈出li在ul中所處的位置即索引值。
html代碼:
- <ul>
- <li>001</li>
- <li>002</li>
- <li>003</li>
- </ul>
js代碼:
示例1:
請看下面的代碼,運行后發現,無論點擊那個li,結果都是3了。
- var aLi = document.getElementsByTagName('li');
- for (var i = 0; i<aLi.length; i++) {
- aLi[i].onclick = function() {
- alert(i);
- }
- }
因為在匿名函數里面并沒有i變量,所以當for結束后,我們再去點擊頁面的li標簽,此時i早就是3了。
示例2:
- aLi[i].onclick = (function(i){
- return function(){
- alert(i);
- }
- })(i);
這次的做法是把函數當返回值,通過自執行函數的參數,把變量i傳進去,然后因為返回函數要引用這個i變量,所以當for循環結束也不會釋放i變量。即在內存中保存了i變量的值。基于這樣的原理,很容易在低版本ie中造成內存泄露。
示例3:
- for (var i = 0; i<aLi.length; i++) {
- (function(i){
- aLi[i].onclick = function(){
- alert(i);
- }
- })(i);
- }
這個原理和上面大同小異。
小米前端閉包面試題:
- function repeat (func, times, wait) {
- } //這個函數能返回一個新函數,比如這樣用
- var repeatedFun = repeat(alert, 10, 5000)
- //調用這個 repeatedFun ("hellworld")
- //會alert十次 helloworld, 每次間隔5秒
我的答案:
- function repeat (func, times, wait) {
- return function(str) {
- while (times >0) {
- setTimeout(function(){
- func(str);
- },wait);
- times--;
- }
- }
- }
- var repeatedFun = repeat(alert, 10, 100);
- repeatedFun ("hellworld");
以上所述就是本文的全部內容了,希望對大家學習javascript閉包能夠有所幫助。
新聞熱點
疑難解答
圖片精選