閉包

閉包定義:有權(quán)訪問另一個(gè)函數(shù)作用域中的變量的函數(shù)

引子

 function createFunctions(){
   var result = new Array();

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

var arr = createFunction();
arr[0]();
arr[1]();
...

分析: 表面看悼粮,似乎每個(gè)數(shù)組都應(yīng)該返回自己的索引值,即位置0的函數(shù)返回0烙荷,位置1的函數(shù)返回1...产舞。但實(shí)際上是:每個(gè)數(shù)組的函數(shù)返回的都是10;這是因?yàn)椋寒?dāng)調(diào)用createFunction之后讨跟,arr[i]中每個(gè)函數(shù)引用的都是同一個(gè)變量i纪他。而此時(shí)變量i的值是10。

 function createFunctions(){
   var result = new Array();

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

var arr = createFunction();
arr[0]();
arr[1]();

分析:重寫了createFunction函數(shù)之后晾匠,每個(gè)函數(shù)返回的就是各自不同的索引值了茶袒。在這個(gè)版本中,我們沒有直接把閉包賦值給數(shù)組凉馆,而是定義了一個(gè)匿名函數(shù)薪寓,并將立即執(zhí)行該匿名函數(shù)的結(jié)果賦給數(shù)組亡资。這里匿名函數(shù)有一個(gè)參數(shù),也就是最終的函數(shù)要返回的值向叉。在調(diào)用每個(gè)匿名函數(shù)時(shí)锥腻,我們傳入了變量i。由于函數(shù)參數(shù)是按值傳遞的母谎。所以num的值就是每次調(diào)用時(shí)變量i的值瘦黑。而在這個(gè)匿名函數(shù)內(nèi)部,又創(chuàng)建并返回了一個(gè)訪問num的閉包奇唤。這樣一來幸斥,arr數(shù)組中每個(gè)函數(shù)都有自己num變量的一個(gè)副本。因此就可以返回各自不同的數(shù)值咬扇。

閉包的作用:

function outer() {
  var i = 100;
  function inner() {
    console.log(i++);
  }
  return inner;
}
var rs = outer();
rs(); //100
rs(); //101
rs(); //102

解釋:outer 是inner的父函數(shù)甲葬,inner被賦給了一個(gè)全局變量,導(dǎo)致inner會一直在內(nèi)存中懈贺,而inner的存在依賴于outer,因此outer也始終在內(nèi)存中演顾,不會在調(diào)用結(jié)束后被垃圾回收機(jī)制回收。

作用:

  • 是可以讀取其他函數(shù)內(nèi)部的變量
  • 另一個(gè)是讓這些變量的值始終保持在內(nèi)存中隅居。

接下來讓我們看看閉包的一些形式:
閉包一

function f(){
  var b = "b";
  return function(){
    return b;
  }
}
console.log(b);
//b is not defined

接下來,我們來看下f的返回值葛虐。這是另外一個(gè)函數(shù)胎源,該函數(shù)有自己的私有空間,同時(shí)也可以訪問f()的空間和全局空間屿脐,所以b對它來說是可見的涕蚤。因?yàn)閒()是可以在全局空間被調(diào)用的(它是一個(gè)全局函數(shù)),所以我們可以將它的返回值賦值給另一個(gè)全局變量的诵,從而生成一個(gè)可以訪問f()私有空間的新全局函數(shù)万栅。

var n = f();
n();
//b

閉包二
下面這個(gè)例子的最終結(jié)果與之前的結(jié)果相同,但是在實(shí)現(xiàn)方法上存在一些細(xì)微的不同西疤。在這里f()不再返回函數(shù)了烦粒,而是直接在函數(shù)體內(nèi)創(chuàng)建一個(gè)新的全局函數(shù)。

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

我們在f() 中定義了一個(gè)新的函數(shù)代赁,并且沒有在這里使用var語句扰她,因此它應(yīng)該是屬于全局的。由于n()是在f()內(nèi)部定義的芭碍,它可以訪問f()的作用域徒役,所以即使該函數(shù)后來升級成了全局函數(shù),但它依然可以保留對f()作用域的訪問權(quán)窖壕。

閉包三
如果一個(gè)函數(shù)需要在其父級函數(shù)返回之后留住對父級作用域的鏈接的話忧勿,就必須要為此建立一個(gè)閉包杉女。
由于函數(shù)通常都會將自身的參數(shù)視為局部變量,因此我們創(chuàng)建返回函數(shù)時(shí)候鸳吸,也可以令其返回父級函數(shù)的參數(shù)熏挎。例如:

function f(arg){
  var n = function(){
    return arg;
  };
  arg++;
  return n;
}
var m = f(123);
m();

循環(huán)中的閉包
例如:

function f(){
  var a = [];
  var i;
  for(i = 0; i < 3; i++)
  {
    a[i] = function(){
      return i;
    }
  }
  return a;
}
var a = f();
a[0]  // 3
a[1]  // 3
a[2]  // 3

原來我們在這里創(chuàng)建三個(gè)閉包,它們都指向了一個(gè)共同的局部變量i层释。但是婆瓜,閉包并不會記錄它們的值,它們所擁有的只是一個(gè)i的鏈接(也是引用), 因此只能返回i的當(dāng)前值贡羔。由于循環(huán)結(jié)束時(shí)i的值為3廉白,所以這三個(gè)函數(shù)都指向了這一共同的值。
解決方案一

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

解決方案二

function f(){
  function makeClosure(x){
    return function(){
      return x;
    }
  }
  var a = [];
  var i;
  for(i = 0; i < 3; i++){
    a[i] = makeClosure(i);
  }
  return a;
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末乖寒,一起剝皮案震驚了整個(gè)濱河市猴蹂,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌楣嘁,老刑警劉巖磅轻,帶你破解...
    沈念sama閱讀 219,539評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異逐虚,居然都是意外死亡聋溜,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,594評論 3 396
  • 文/潘曉璐 我一進(jìn)店門叭爱,熙熙樓的掌柜王于貴愁眉苦臉地迎上來撮躁,“玉大人,你說我怎么就攤上這事买雾“崖” “怎么了?”我有些...
    開封第一講書人閱讀 165,871評論 0 356
  • 文/不壞的土叔 我叫張陵漓穿,是天一觀的道長嗤军。 經(jīng)常有香客問我,道長晃危,這世上最難降的妖魔是什么叙赚? 我笑而不...
    開封第一講書人閱讀 58,963評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮山害,結(jié)果婚禮上纠俭,老公的妹妹穿的比我還像新娘。我一直安慰自己浪慌,他們只是感情好冤荆,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,984評論 6 393
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著权纤,像睡著了一般钓简。 火紅的嫁衣襯著肌膚如雪乌妒。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,763評論 1 307
  • 那天外邓,我揣著相機(jī)與錄音撤蚊,去河邊找鬼。 笑死损话,一個(gè)胖子當(dāng)著我的面吹牛侦啸,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播丧枪,決...
    沈念sama閱讀 40,468評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼光涂,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了拧烦?” 一聲冷哼從身側(cè)響起忘闻,我...
    開封第一講書人閱讀 39,357評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎恋博,沒想到半個(gè)月后齐佳,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,850評論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡债沮,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,002評論 3 338
  • 正文 我和宋清朗相戀三年炼吴,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片疫衩。...
    茶點(diǎn)故事閱讀 40,144評論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡缺厉,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出隧土,到底是詐尸還是另有隱情,我是刑警寧澤命爬,帶...
    沈念sama閱讀 35,823評論 5 346
  • 正文 年R本政府宣布曹傀,位于F島的核電站,受9級特大地震影響饲宛,放射性物質(zhì)發(fā)生泄漏皆愉。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,483評論 3 331
  • 文/蒙蒙 一艇抠、第九天 我趴在偏房一處隱蔽的房頂上張望幕庐。 院中可真熱鬧,春花似錦家淤、人聲如沸异剥。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,026評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽冤寿。三九已至歹苦,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間督怜,已是汗流浹背殴瘦。 一陣腳步聲響...
    開封第一講書人閱讀 33,150評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留号杠,地道東北人蚪腋。 一個(gè)月前我還...
    沈念sama閱讀 48,415評論 3 373
  • 正文 我出身青樓,卻偏偏與公主長得像姨蟋,于是被迫代替她去往敵國和親屉凯。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,092評論 2 355

推薦閱讀更多精彩內(nèi)容