DIV CSS 佈局教程網

 DIV+CSS佈局教程網 >> 網頁腳本 >> JavaScript入門知識 >> JavaScript基礎知識 >> 深刻理解JavaScript---閉包
深刻理解JavaScript---閉包
編輯:JavaScript基礎知識     

 

JavaScript  

閉包是指那些能夠訪問獨立(自由)變量的函數 (變量在本地使用,但定義在一個封閉的作用域中)。換句話說,這些函數可以“記憶”它被創建時候的環境。——這句話其實有點難以理解。我覺得應該用一些例子來理解閉包的含義。

  • 閉包#1

先來看一個函數:

function f(){ var b = "b"; return function(){ return b; } }

 

這個函數含有一個局部變量b,它在全局空間裡面是不可見的。而f()的返回值是另一個匿名函數,該函數有自己的私有的空間,可以訪問f()的空間和全局空間,所以b對它來說是可見的。

var n = f(); n();//此時控制台輸出"b"

 

因為f()是一個全局函數,它可以在全局空間被調用,當然也可以將其返回值賦值給另一個全局變量n,從而生成一個可以訪問f()私有空間的新的全局函數。

  • 閉包#2

再來看看下面這個跟上面差不多的函數,在這裡f()不再返回函數了,而是直接在函數體內創建一個新的全局函數

var n; function f(){ var b = "b"; n = function(){ return b; } } f(); n();//調用f(),然後再調用n(),控制台輸出"b"

 

由於n()沒有使用var語句,因此它是全局的,同時它也可以訪問f()的作用域,所以哪怕n()最後升級為全局函數,但它依然可以保留對f()作用域的訪問權。

  • 閉包#3

函數通常會讓自身的參數視為局部變量,所以我們創建返回函數時,也可以令其返回父級函數的參數,例如:

function f(arg){ var n = function(){ return arg; }; arg++; return n; } var m = f(123); m();//調用函數,輸出124

 

有一點很重要:n被賦值時函數並沒有被調用,調用發生是在n被求值,也就是執行return n;語句時。由此可以看出,函數所綁定的是作用域本身,而不是該作用域中的變量或變量當前所返回的值。

  • 循環中的閉包#4

這種閉包所導致的bug往往很難被發現,因為它們表面上看起來很正常,來看一下下面的函數

function f(){ var a = []; var i; for (i = 0; i < 3; i++){ a[i] = function(){ return i; } } return a; } //下面來運行一下函數,並將結果賦值給數組a var a = f(); a[0]();//輸出3 a[1]();//輸出3 a[2]();//輸出3

 

為啥不是0、1、2呢?為啥會這樣呢?原來在這裡創建的三個閉包,它們都指向了一個共同的局部變量i,但是,閉包不會記錄它們的值,它們所擁有的的只是一個i的連接(即引用),因此只能返回i當前值,因為i結束循環時值為3,所以這三個函數都指向一個共同值3

如何糾正?顯然,需要a[i]指向三個不同的變量,下面是解決方案之一:

function f(){ var a = []; var i; for (i = 0; i < 3; i++){ a[i] = (function(x){ return function(){ return x; } })(i); } return a; } //下面來運行一下函數,並將結果賦值給數組a var a = f(); a[0]();//輸出0 a[1]();//輸出1 a[2]();//輸出2

 

這裡使用了自調函數,不再直接返回i的值,而是將i傳遞給自調函數,i賦值給了局部變量x,這樣一來,每次迭代x就會擁有各自不同的值了。

解決方案二:

function f(){ function aa(x){ return function(){ return x; } } var a = []; var i; for (i = 0; i < 3; i++){ a[i] = aa(i); } return a; }

 

方案二不使用自調函數,而是定義了一個內部函數實現相同的功能,每次迭代操作中,將i的值“本地化”。

  • Getter與Setter、 迭代器 閉包的應用示例#5
var getValue, setValue; (function(){ var temp = 0; getValue = function(){ return temp; }; setValue = function(v){ temp = v; } })(); getValue();//輸出0 setValue(123) getValue();//輸出123

這個例子是通過一個匿名自調函數來實現的,定義的全局函數setValue()和getValue(),確保局部變量temp的不可直接訪問性。

下面是一個接受數組輸入的初始化函數,其中定義了一個私有指針,該指針會指向數組中的下一個元素。

function setup(x){ var i = 0; return function() { return x[i++]; }; } //調用setup(),創建我們所需的next()函數 var next = setup(['a', 'b', 'c']); //重復調用next(),就可以不停的獲取下一個元素 next();//輸出"a" next();//輸出"b" next();//輸出"c"

 

到這裡閉包就暫時告一段落了,以後有新的理解再寫。

XML學習教程| jQuery入門知識| AJAX入門| Dreamweaver教程| Fireworks入門知識| SEO技巧| SEO優化集錦|
Copyright © DIV+CSS佈局教程網 All Rights Reserved