匿名函數: 之前的文章也有講到,指的是 沒有函數名的函數 嵌套函數呢 ? 請看代碼: 如代碼所示,函數內部嵌入函數,稱之為嵌套函數。 那閉包又是什麼呢? 不多說,看代碼 這麼看,感覺像是,只要是嵌套函數,且能訪問上一層作用域的變數就是閉包。 是這樣嗎? 我們知道,js中,分為全局作用域,局部作用域, ...
匿名函數: 之前的文章也有講到,指的是 沒有函數名的函數
1 function (){ console.log('匿名函數') }
嵌套函數呢 ? 請看代碼:
1 function test (){ 2 var sum = 20; 3 //內嵌函數 4 demo = function(){ 5 alert(sum); 6 console.log('我是嵌套函數'); 7 } 8 }
如代碼所示,函數內部嵌入函數,稱之為嵌套函數。
那閉包又是什麼呢?
不多說,看代碼
1 function demo(){ 2 var num = 0; 3 4 // 返回一個函數 5 return function(){ 6 alert( num+1 ); 7 } 8 9 } 10 //將返回的函數賦值給 add 變數 11 var add = demo(); 12 // add就是一個閉包 13 add();
這麼看,感覺像是,只要是嵌套函數,且能訪問上一層作用域的變數就是閉包。 是這樣嗎?
我們知道,js中,分為全局作用域,局部作用域,每個函數也就相等於一個局部作用域。
同理,變數,也分為全局變數和局部變數。 有什麼區別呢?
在瀏覽器中,全局作用域對象是 window,也就是說頁面一打開,window對象就存在。
在js中,每個函數是局部作用域,局部變數會隨著 函數的執行創建和執行完畢後銷毀。
而全局變數,只要頁面不關閉,則會一直存在。並不會隨著函數的執行完畢而銷毀。
那麼和閉包有什麼關係呢?
在 “javaScript高級程式” 這本書有講到過“作用域鏈”的概念, 特殊之處,在於函數內部可以直接讀取全局變數。
而函數外部卻不能讀取函數內部的變數。
也就是說,作用域鏈就像只能往上不能往下的階梯。我們看段代碼理解
1 var name = "window"; 2 var age = 20; 3 dmeo(); 4 function demo(){ 5 var age = 21; 6 console.log(name); // window 7 console.log(age); //21 8 }
在執行 demo() 函數時,就會創建一個通往全局作用域鏈,保存著當前作用域的變數,以便查找返回。
在執行 console.log( name ) 這段代碼時,會搜尋當前作用域( demo函數 ) 中是否存在 name 變數,因當前作用域不存在,所以在往上找到全局變數 name ,因此返回 window;
在執行 console.log( age ) 這段代碼時, 也會搜尋 當前作用域(demo函數) 中是否存在 age 變數,因為存在,所以返回 21。
既然機制是只能往上讀, 那麼考慮一個問題,怎麼在外部讀取內部函數的變數呢?
辦法不是沒有,稍微變通下即可。這就需要用到閉包的概念,
1 function f1(){ 2 var num = 0 ; 3 //定義內部函數 4 function f2(){ 5 return num + 1; 6 } 7 //返回 f2函數引用 8 retufn f2; 9 } 10 11 // bar 變數也指向 f2 函數,在此也是一個閉包 12 var bar = f1(); 13 14 //執行 15 bar(); // 1;
我們知道,函數中的變數會隨著函數的執行完畢後會被銷毀。而如上代碼,f1()函數執行完畢後,將f2函數賦值給一個全局變數,而f2函數的變數又依賴f1的num變數,因此,f1
中的num變數並不會隨著f1的函數執行完畢後而銷毀。
這裡借用 “阮一峰” 大神的題目藉此解析加深理解。
鏈接: 學習javaScript閉包
1 var name = "the window"; 2 3 var obj = { 4 name : 'the obj', 5 getName : function(){ 6 return funciton(){ 7 return this.name; 8 } 9 } 10 } 11 12 //執行 getName返回的函數 13 alert(obj.getName()());
我們看調用函數分析, 分成兩部分執行。 先來看 obj.getName(); 此時getName函數由 obj對象調用,因此this的值是 obj。 但此時並不是輸出而是返回一個函數。
再加上一個(); 執行返回的函數,但此時返回的函數並沒有任何對象調用,當不是對象本身調用,this的值會被提升到 window對象。因此輸出的是 “the window"
var name = "the Window"; var obj = { name : "the obj", getName : funciton(){ var that = this; return function(){ return that.name; } } } //執行 getName 返回的函數 alert(obj.getName()());
看了上面的題目,這個應該 小意思吧, 你說呢 ?