重拾ECMAScript基礎(chǔ)——閉包與匿名函數(shù)

ECMAScript中經(jīng)常把閉包與匿名函數(shù)混用,所以很多時(shí)候會(huì)搞不清這兩個(gè)概念

閉包是指有權(quán)訪(fǎng)問(wèn)另一個(gè)函數(shù)作用域中的變量的函數(shù)。——《JS高程》

Closures (閉包)是使用被作用域封閉的變量,函數(shù),閉包等執(zhí)行的一個(gè)函數(shù)的作用域。通常我們用和其相應(yīng)的函數(shù)來(lái)指代這些作用域。(可以訪(fǎng)問(wèn)獨(dú)立數(shù)據(jù)的函數(shù))
閉包是一個(gè)函數(shù)和聲明該函數(shù)的詞法環(huán)境的組合。從理論角度來(lái)說(shuō),所有函數(shù)都是閉包。
——MDN https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Closures

函數(shù)表達(dá)式

JavaScript中聲明函數(shù)有兩種方式

// 1.函數(shù)聲明
function functionName(arg0, arg1, arg2) {
  //函數(shù)體
}
// 2.匿名函數(shù)賦值
var functionName = function(arg0, arg1, arg2){
  //函數(shù)體
}

作用域鏈

在函數(shù)執(zhí)行過(guò)程中,需要在作用域鏈中查找變量:

function compare(value1, value2){
   if (value1 < value2){
     return -1;
   } else if (value1 > value2){
     return 1;
   } else {
     return 0;
   }
}
var result = compare(5, 10); 
作用域鏈.png

當(dāng)函數(shù)執(zhí)行完畢后,局部活動(dòng)對(duì)象就會(huì)被銷(xiāo)毀,內(nèi)存中僅保存全局作用域(全局執(zhí)行環(huán)境的變量對(duì)象);

閉包

而閉包有所不同

閉包是一種特殊的對(duì)象。它由兩部分構(gòu)成:函數(shù),以及創(chuàng)建該函數(shù)的環(huán)境。環(huán)境由閉包創(chuàng)建時(shí)在作用域中的任何局部變量組成。

function createComparisonFunction(propertyName) {

   return function(object1, object2){
     var value1 = object1[propertyName];
     var value2 = object2[propertyName];

     if (value1 < value2){
       return -1;
     } else if (value1 > value2){
       return 1;
     } else {
       return 0;
     }
   };
 } 

var compare = createComparisonFunction("name");
var result = compare({ name: "Nicholas" }, { name: "Greg" }); 

createComparisonFunction這個(gè)函數(shù)中,返回的匿名函數(shù)賦值給了compare這個(gè)變量,我們可以說(shuō)compare是一個(gè)閉包。
返回的匿名函數(shù)的作用域鏈中可以訪(fǎng)問(wèn)在createComparisonFunction中的所有變量,而且函數(shù)在執(zhí)行完畢后,其活動(dòng)對(duì)象也不會(huì)被銷(xiāo)毀,因?yàn)槟涿瘮?shù)的作用域鏈仍然在引用這個(gè)活動(dòng)對(duì)象。
直到匿名函數(shù)被銷(xiāo)毀后,createComparisonFunction()的活動(dòng)對(duì)象才會(huì)被銷(xiāo)毀;

//創(chuàng)建函數(shù)
var compareNames = createComparisonFunction("name");
//調(diào)用函數(shù)
var result = compareNames({ name: "Nicholas" }, { name: "Greg" });
//解除對(duì)匿名函數(shù)的引用(以便釋放內(nèi)存)
compareNames = null; 

首先,創(chuàng)建的比較函數(shù)被保存在變量compareNames 中。而通過(guò)將compareNames 設(shè)置為等于null
解除該函數(shù)的引用,就等于通知垃圾回收例程將其清除。隨著匿名函數(shù)的作用域鏈被銷(xiāo)毀,其他作用域
(除了全局作用域)也都可以安全地銷(xiāo)毀了。


作用域鏈.png

閉包與匿名函數(shù)

在開(kāi)發(fā)中,我們常會(huì)用到這樣的寫(xiě)法

(function () {
    // ... all vars and functions are in this scope only
    // still maintains access to all globals
}());

這里聲明匿名函數(shù)立即執(zhí)行,使得局部變量不會(huì)污染到全局變量,并可以訪(fǎng)問(wèn)全局變量(外部變量);

var num = 1;
(function () {
    var num = 2;
    console.log(num); // 2
}())
console.log(num); // 1

匿名函數(shù)通常與閉包一起使用,但并無(wú)必然聯(lián)系;
因?yàn)殚]包保存的是變量對(duì)象,所以我們往往要用匿名函數(shù)立即執(zhí)行來(lái)保存過(guò)程中的值;(見(jiàn)需要注意)

閉包的實(shí)用

想了想,自己總結(jié)的不如直接看文檔。
MDN 文檔 https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Closures

  1. 在函數(shù)中給事件驅(qū)動(dòng)型的變量添加函數(shù);
  2. 模擬私有方法

需要注意

作用域鏈的這種配置機(jī)制引出了一個(gè)值得注意的副作用,即閉包只能取得包含函數(shù)中任何變量的最后一個(gè)值。 ——《JS高程》

因?yàn)殚]包所保存的是整個(gè)變量對(duì)象;

function createFunctions(){
   var result = new Array();
   for (var i=0; i < 10; i++){
   result[i] = function(){
       return i;
     };
   }
   return result;
} 

//都是10

我們必須通過(guò)匿名函數(shù)的立即執(zhí)行來(lái)進(jìn)行保存

function createFunctions(){
   var result = new Array();
   for (var i=0; i < 10; i++){
     result[i] = function(num){
       return function(){
         return num;
       };
     }(i);
   }
   return result;
} 

//1-10

當(dāng)然,ES6可以使用let來(lái)替代

function createFunctions(){
   var result = new Array();
   for (let i=0; i < 10; i++){
   result[i] = function(){
       return i;
     };
   }
   return result;
} 
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀(guān)點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 王福朋 - 博客園 —— 《 深入理解javascript原型和閉包》 目錄:深入理解javascript原型和閉...
    帥而不花__美而不浪閱讀 1,634評(píng)論 0 2
  • 函數(shù)作用域 要理解閉包,必須從理解函數(shù)被調(diào)用時(shí)都會(huì)發(fā)生什么入手。 我們知道,每個(gè)javascript函數(shù)都是一個(gè)對(duì)...
    黎貝卡beka閱讀 572評(píng)論 0 2
  • 談起閉包,它可是JavaScript兩個(gè)核心技術(shù)之一(異步和閉包),在面試以及實(shí)際應(yīng)用當(dāng)中,我們都離不開(kāi)它們,甚至...
    sponing閱讀 777評(píng)論 0 7
  • 屠哥說(shuō)這個(gè)周末去一下美輪美奐的南山路,對(duì)于杭州我們總有一些期待,還有更多的回憶。 第一次迷失杭州是在柳浪聞鶯一次集...
    牛貓貓閱讀 209評(píng)論 0 0
  • 屋檐下的小孩,一張木板凳,那是他的童年,回憶中的孤獨(dú),如濕潤(rùn)的泥土的氣息,疲倦的飄散出來(lái)。
    Forget盡管走下去閱讀 246評(píng)論 1 1

友情鏈接更多精彩內(nèi)容