技術頻道導航
HTML/CSS
.NET技術
IIS技術
PHP技術
Js/JQuery
Photoshop
Fireworks
服務器技術
操作系統(tǒng)
網(wǎng)站運營

贊助商

分類目錄

贊助商

最新文章

搜索

一個示例,就能讓你了解JS閉包的功能作用是什么

作者:admin    時間:2022-6-3 7:24:58    瀏覽:

在一個函數(shù)外面加一個括號,就成為了一個閉包,說實在的,閉包函數(shù)在實際編程中用得并不多,但是這卻是學習JavaScript必須掌握的知識,并且,閉包是前端考試/面試的必考題。因此,我們要學會和懂得使用這個知識點。在本文中,將通過一個示例,讓你了解閉包的功能作用是什么。

一個示例,讓你了解JS閉包的功能作用是什么

示例

場景設計:有個函數(shù)體是一個計數(shù)器,我現(xiàn)在要讓計數(shù)器初始值增加3,如何編寫代碼?

普通函數(shù)實現(xiàn)的思路

使用普通函數(shù)實現(xiàn)的思路是這樣:

var counter = 0;
function add() {
   return counter += 1;
}
add();
add();
add();// 計數(shù)器現(xiàn)在為 3

輸出

現(xiàn)在我們已經(jīng)達到了目的,可是問題來了,代碼中的任何一個函數(shù)都可以隨意改變counter的值,因為counter是一個全局變量,所以這個計數(shù)器并不完美。那我們把counter放在add函數(shù)里面不就好了么?

function add() {
    var counter = 0;
    return counter += 1;

add();
add();
add();// 本意是想輸出 3, 但輸出的都是 1 

輸出

所以這樣做的話,每次調用add函數(shù),counter的值都要被初始化為0,還是達不到我們的目的。

使用閉包的實現(xiàn)思路

這時候我們可以用閉包去解決這個問題了,先看代碼。

var add = (function () {
    var counter = 0;
    return function () {return counter += 1;}
})();
add();
add();
add();// 計數(shù)器為 3

這時候我們完美實現(xiàn)了計數(shù)器。這段非常精簡,可以拆分成如下等價代碼。

function outerFunction () {
     var counter = 0;
     function innerFunction (){
         return counter += 1;
     }
     return innerFunction;
}
var add = outerFunction();
add();
add();
add();// 計數(shù)器為 3

輸出

這時候的add就形成了一個閉包。一個閉包由兩部分組成,函數(shù)和創(chuàng)建該函數(shù)的環(huán)境。環(huán)境是由環(huán)境中的局部變量組成的。對于閉包add來說,它由函數(shù)innerFunction和變量counter組成,所以這時候add是可以訪問變量counter的。

結論

所以閉包的功能就是使一個函數(shù)能訪問另一個函數(shù)作用域中的變量。形成閉包之后,該變量不會被垃圾回收機制回收。

閉包的原理其實還是作用域。

知識擴展

什么是閉包

一個函數(shù)和對其周圍狀態(tài)(lexical environment,詞法環(huán)境)的引用捆綁在一起(或者說函數(shù)被引用包圍),這樣的組合就是閉包(closure)。也就是說,閉包讓你可以在一個內(nèi)層函數(shù)中訪問到其外層函數(shù)的作用域。在 JavaScript 中,每當創(chuàng)建一個函數(shù),閉包就會在函數(shù)創(chuàng)建的同時被創(chuàng)建出來。

詞法作用域

請看下面的代碼:

function init() {
  var name = "WebKaka"; // name 是一個被 init 創(chuàng)建的局部變量
  function displayName() { // displayName() 是內(nèi)部函數(shù),一個閉包
      console.log(name); // 使用了父函數(shù)中聲明的變量
  }
  displayName();
}
init();

輸出

init() 創(chuàng)建了一個局部變量 name 和一個名為 displayName() 的函數(shù)。displayName() 是定義在 init() 里的內(nèi)部函數(shù),并且僅在 init() 函數(shù)體內(nèi)可用。請注意,displayName() 沒有自己的局部變量。然而,因為它可以訪問到外部函數(shù)的變量,所以 displayName() 可以使用父函數(shù) init() 中聲明的變量 name 。

運行該代碼后發(fā)現(xiàn), displayName() 函數(shù)內(nèi)的 log() 語句成功顯示出了變量 name 的值(該變量在其父函數(shù)中聲明)。這個詞法作用域的例子描述了分析器如何在函數(shù)嵌套的情況下解析變量名。詞法(lexical)一詞指的是,詞法作用域根據(jù)源代碼中聲明變量的位置來確定該變量在何處可用。嵌套函數(shù)可訪問聲明于它們外部作用域的變量。

示例

現(xiàn)在來看以下例子 :

function makeFunc() {
    var name = "WebKaka";
    function displayName() {
        console.log(name);
    }
    return displayName;
}

var myFunc = makeFunc();
myFunc();

輸出

 

運行這段代碼的效果和之前 init() 函數(shù)的示例完全一樣。其中不同的地方(也是有意思的地方)在于內(nèi)部函數(shù) displayName() 在執(zhí)行前,從外部函數(shù)返回。

第一眼看上去,也許不能直觀地看出這段代碼能夠正常運行。在一些編程語言中,一個函數(shù)中的局部變量僅存在于此函數(shù)的執(zhí)行期間。一旦 makeFunc() 執(zhí)行完畢,你可能會認為 name 變量將不能再被訪問。然而,因為代碼仍按預期運行,所以在 JavaScript 中情況顯然與此不同。

原因在于,JavaScript 中的函數(shù)會形成了閉包。 閉包是由函數(shù)以及聲明該函數(shù)的詞法環(huán)境組合而成的。該環(huán)境包含了這個閉包創(chuàng)建時作用域內(nèi)的任何局部變量。在本例子中,myFunc 是執(zhí)行 makeFunc 時創(chuàng)建的 displayName 函數(shù)實例的引用。displayName 的實例維持了一個對它的詞法環(huán)境(變量 name 存在于其中)的引用。因此,當 myFunc 被調用時,變量 name 仍然可用,其值 WebKaka 就被傳遞到log中。

相關文章

標簽: 閉包  
x
  • 站長推薦
/* 左側顯示文章內(nèi)容目錄 */