Javascript閉包(Closure),是許多開發人員理解和應用起來都相對比較困難的一個概念。但是一旦理解了這個概念,我們就會發現它離我們的日常開發非常近。這篇文章為大家介紹Javascript閉包,從定義、原理、實際應用等多個方面展開。
那么,什么是閉包呢?我們可以簡單地理解成一個函數能夠訪問在當前詞法作用域外層的變量,這就形成了一個閉合的作用域。比如,下面這段代碼就是一個閉包:
function outerFunction() { var outerVariable = 'Hello World'; function innerFunction() { console.log(outerVariable); } return innerFunction; } var innerFunc = outerFunction(); innerFunc(); // 輸出:'Hello World'
在這段代碼中,innerFunction可以訪問到外層的outerVariable變量,這就是一個閉包。我們甚至可以在innerFunction以外的地方調用outerFunction,從而獲得innerFunction,并且innerFunction還能記住它的上下文。
為了更好地理解閉包,可以看下面這個例子:
function createIncrement() { var counter = 0; return function() { counter++; console.log(counter); }; } var increment = createIncrement(); increment(); // 輸出:1 increment(); // 輸出:2 increment(); // 輸出:3
這里,createIncrement函數返回一個內部函數,它可以訪問外部函數createIncrement的計數器變量。當我們調用increment函數時,它每次都會增加計數器并且輸出計數器的值。這就是一個閉包的例子。
在JavaScript中,每次當函數被調用時,都會創建一個新的詞法作用域(也就是調用棧)。當函數執行完畢,這個作用域就會被銷毀,并且其中的變量也會隨之消失。但是閉包的特殊之處在于,它允許內層函數訪問外層函數的變量,所以這些變量就可以一直駐留在內存中。
除了可以創建私有變量和函數外,閉包還有其他的應用。比如,我們可以使用閉包來創建一個私有變量的緩存,而不是在全局作用域中使用變量。
var expensiveFunc = (function() { var cachedResult = null; return function() { if (cachedResult === null) { // 模擬耗時的計算 var result = 0; for (var i = 0; i < 100000000; i++) { result += i; } cachedResult = result; } return cachedResult; }; })(); console.log(expensiveFunc()); // 輸出結果:4999999950000000 console.log(expensiveFunc()); // 輸出結果:4999999950000000
這里,expensiveFunc函數模擬了一個耗時的計算,而且只有在第一次調用時才會進行。當cachedResult有值時,函數就會直接返回之前計算的結果,而不是重新開始耗時的計算。這就傳說中的“記憶函數”。
在實際開發中,使用閉包的場景很多,希望本篇文章能夠讓大家感受到閉包的魅力,并在以后的開發中更加熟練地運用這個重要的概念。