function f(x) { //外部函數 return function (y) { //內部函數,通過返回內部函數,實現外部參照 return x + y; //存取外部函數的引數 }; } var c = f(5); //呼叫外部函數,獲取參照內部函數 console.log(c(6)); //呼叫內部函數,原外部函數的引數繼續存在解析過程簡單描述如下:
var c; //宣告全域性變數 function f(x) { //外部函數 c = function (y) { //內部函數,通過向全域性變數開放實現外部參照 return x + y; //存取外部函數的引數 }; } f(5); //呼叫外部函數 console.log(c(6)); //使用全域性變數c呼叫內部函數,返回11
var add; //全域性變數 function f() { //外部函數 var a = [1,2,3]; //私有變數,參照型陣列 add = function (x) { //測試函數,對外開放 a[0] = x * x; //修改私有陣列的元素值 } return a; //返回私有陣列的參照 } var c = f(); console.log(c[0]); //讀取閉包內陣列,返回1 add(5); //測試修改陣列 console.log(c[0]); //讀取閉包內陣列,返回25 add(10); //測試修改陣列 console.log(c[0]); //讀取閉包內陣列,返回100與函數相同,物件和陣列也是參照型資料。呼叫函數 f,返回私有陣列 a 的參照,即傳值給區域性變數 c,而 a 是函數 f 的私有變數,當被呼叫後,活動物件繼續存在,這樣就形成了閉包。
這種特殊形式的閉包沒有實際應用價值,因為其功能單一,只能作為一個靜態的、單向的閉包。而閉包函數可以設計各種複雜的運算表示式,它是函數式變成的基礎。
反之,如果返回的是一個簡單的值,就無法形成閉包,值傳遞是直接複製。外部變數 c 得到的僅是一個值,而不是對函數內部變數的參照。這樣當函數呼叫後,將直接登出物件。function f(x) { //外部函數 var a = 1; //私有變數 return a; } var c = f(5); console.log(c); //僅是一個值,返回1
var f = function () { //外部函數 var a = []; //私有陣列初始化 return function (x) { //返回內部函數 a.push(x); //新增元素 return a; //返回私有陣列 }; } () //直接呼叫函數,生成執行環境 var a = f(1); //新增值 console.log(a); //返回1 var b = f(2); //新增值 console.log(b); //返回1,2在上面範例中,通過外部函數設計一個閉包,定義一個永久的記憶體。當呼叫外部函數生成執行環境之後,就可以利用返回的匿名函數不斷地的向閉包體內的陣列 a 傳入新值,傳入的值會持續存在。
<script> function f() { var a = 1; b = function () { console.log("a =" + a); } c = function () { a ++; } d = function () { a --; } } </script> <button onclick="f()">生成閉包</button> <button onclick="b()">檢視 a 的值</button> <button onclick="c()">遞增</button> <button onclick="d()">遞減</button>在瀏覽器中瀏覽時,首先點選“生成閉包”按鈕,生成一個閉包;點選“檢視 a 的值”按鈕,可以隨時檢視閉包內私有變數 a 的值;點選“遞增”“遞減”按鈕時,可以動態修改閉包內變數 a 的值,效果如圖所示。