匿名函數: 之前的文章也有講到,指的是 沒有函數名稱的函數
function (){ console.log('匿名函数') }
巢狀函數呢 ? 請看程式碼:
function test (){ var sum = 20; //内嵌函数 demo = function(){ alert(sum); console.log('我是嵌套函数'); } }
如程式碼所示,函數內部嵌入函數,稱為巢狀函數。
那閉包又是什麼呢?
不多說,看程式碼
function demo(){ var num = 0; // 返回一个函数 return function(){ alert( num+1 ); } } //将返回的函数赋值给 add 变量 var add = demo(); // add就是一个闭包 add();
這麼看,感覺像是,只要是巢狀函數,且能存取上一層作用域的變數就是閉包。 是這樣嗎?
我們知道,js中,分成全域作用域,局部作用域,每個函數也就相等於一個局部作用域。
同理,變量,也分為全域變數和局部變數。 有什麼區別呢?
在瀏覽器中,全域作用域物件是 window,也就是說頁面一打開,window物件就存在。
在js中,每個函數是局部作用域,局部變數會隨著 函數的執行建立和執行完畢後銷毀。
而全域變量,只要頁面不關閉,就會一直存在。並不會隨著函數的執行完畢而銷毀。
那麼跟閉包有什麼關係呢?
在 “javaScript高級程式” 這本書有講到過「作用域鏈」的概念, 特殊之處,在於函數內部可以直接讀取全域變數。
而函數外部卻無法讀取函數內部的變數。
也就是說,作用域鏈就像是只能往上不能往下的階梯。我們看段程式碼理解
var name = "window"; var age = 20; dmeo(); function demo(){ var age = 21; console.log(name); // window console.log(age); //21 }
在執行 demo() 函數時,就會建立一個通往全域作用域鏈,保存著目前作用域的變量,以便尋找回傳。
在執行console.log( name ) 這段程式碼時,會搜尋目前作用域( demo函數) 中是否存在name 變量,因目前作用域不存在,所以在往上找到全域變數name ,因此返回window;
在執行console.log( age ) 這段程式碼時, 也會搜尋目前作用域(demo函數) 中是否存在age 變量,因為存在,所以返回21。
既然機制是只能往上讀, 那麼考慮一個問題,怎麼在外部讀取內部函數的變數呢?
辦法不是沒有,稍微變通即可。這就需要用到閉包的概念,
function f1(){ var num = 0 ; //定义内部函数 function f2(){ return num + 1; } //返回 f2函数引用 retufn f2; } // bar 变量也指向 f2 函数,在此也是一个闭包 var bar = f1(); //执行 bar(); // 1;
我們知道,函數中的變數會隨著函數的執行完畢後會被銷毀。而如上程式碼,f1()函數執行完畢後,將f2函數賦值給一個全域變量,而f2函數的變數又依賴f1的num變量,因此,f1
中的num變數並不會隨著f1的函數執行完畢後而銷毀。
這裡借用 「阮一峰」 大神的題目藉此解析加深理解。
連結: 學習javaScript閉包
var name = "the window"; var obj = { name : 'the obj', getName : function(){ return funciton(){ return this.name; } } } //执行 getName返回的函数 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()());
以上是匿名函數、巢狀函數、閉包分別是什麼的詳細內容。更多資訊請關注PHP中文網其他相關文章!