閉包

用閉包模擬私有方法

var makeCounter = function() {
  var privateCounter = 0;
  function changeBy(val) {
    privateCounter += val;
  }
  return {
    increment: function() {
      changeBy(1);
    },
    decrement: function() {
      changeBy(-1);
    },
    value: function() {
      return privateCounter;
    }
  }  
};

var Counter1 = makeCounter();
var Counter2 = makeCounter();
console.log(Counter1.value()); /* logs 0 */
Counter1.increment();
Counter1.increment();
console.log(Counter1.value()); /* logs 2 */
Counter1.decrement();
console.log(Counter1.value()); /* logs 1 */
console.log(Counter2.value()); /* logs 0 */

請注意兩個計數器 counter1 和 counter2 是如何維護它們各自的獨立性的。每個閉包都是引用自己詞法作用域內的變量 privateCounter 拍嵌。

每次調用其中一個計數器時,通過改變這個變量的值碘勉,會改變這個閉包的詞法環(huán)境掷匠。然而在一個閉包內對變量的修改,不會影響到另外一個閉包中的變量珊拼。

在循環(huán)中創(chuàng)建閉包厘托,常見的錯誤

<p id="help">Helpful notes will appear here</p>
<p>E-mail: <input type="text" id="email" name="email"></p>
<p>Name: <input type="text" id="name" name="name"></p>
<p>Age: <input type="text" id="age" name="age"></p>
function showHelp(help) {
  document.getElementById('help').innerHTML = help;
}

function setupHelp() {
  var helpText = [
      {'id': 'email', 'help': 'Your e-mail address'},
      {'id': 'name', 'help': 'Your full name'},
      {'id': 'age', 'help': 'Your age (you must be over 16)'}
    ];

  for (var i = 0; i < helpText.length; i++) {
    var item = helpText[i];
    document.getElementById(item.id).onfocus = function() {
      showHelp(item.help);
    }
  }
}

setupHelp();

數組 helpText 中定義了三個有用的提示信息友雳,每一個都關聯(lián)于對應的文檔中的input 的 ID。通過循環(huán)這三項定義铅匹,依次為相應input添加了一個 onfocus 事件處理函數押赊,以便顯示幫助信息。

運行這段代碼后包斑,您會發(fā)現它沒有達到想要的效果流礁。無論焦點在哪個input上,顯示的都是關于年齡的信息罗丰。

原因是賦值給 onfocus 的是閉包神帅。這些閉包是由他們的函數定義和在 setupHelp 作用域中捕獲的環(huán)境所組成的。這三個閉包在循環(huán)中被創(chuàng)建萌抵,但他們共享了同一個詞法作用域找御,在這個作用域中存在一個變量item。當onfocus的回調執(zhí)行時绍填,item.help的值被決定霎桅。由于循環(huán)在事件觸發(fā)之前早已執(zhí)行完畢,變量對象item(被三個閉包所共享)已經指向了helpText的最后一項讨永。

解決這個問題的一種方案是使用更多的閉包:特別是使用前面所述的函數工廠:

function showHelp(help) {
  document.getElementById('help').innerHTML = help;
}

function makeHelpCallback(help) {
  return function() {
    showHelp(help);
  };
}

function setupHelp() {
  var helpText = [
      {'id': 'email', 'help': 'Your e-mail address'},
      {'id': 'name', 'help': 'Your full name'},
      {'id': 'age', 'help': 'Your age (you must be over 16)'}
    ];

  for (var i = 0; i < helpText.length; i++) {
    var item = helpText[i];
    // 這里運用了在一個閉包內對變量的修改滔驶,不會影響到另外一個閉包中的變量。
    document.getElementById(item.id).onfocus = makeHelpCallback(item.help);
  }
}

setupHelp();

避免使用過多的閉包卿闹,可以用let關鍵詞:

function showHelp(help) {
  document.getElementById('help').innerHTML = help;
}

function setupHelp() {
  var helpText = [
      {'id': 'email', 'help': 'Your e-mail address'},
      {'id': 'name', 'help': 'Your full name'},
      {'id': 'age', 'help': 'Your age (you must be over 16)'}
    ];

  for (var i = 0; i < helpText.length; i++) {
    let item = helpText[i];
    document.getElementById(item.id).onfocus = function() {
      showHelp(item.help);
    }
  }
}

setupHelp();

這個例子使用let而不是var揭糕,因此每個閉包都綁定了塊作用域的變量萝快,這意味著不再需要額外的閉包。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末著角,一起剝皮案震驚了整個濱河市杠巡,隨后出現的幾起案子,更是在濱河造成了極大的恐慌雇寇,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,544評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件蚌铜,死亡現場離奇詭異锨侯,居然都是意外死亡,警方通過查閱死者的電腦和手機冬殃,發(fā)現死者居然都...
    沈念sama閱讀 92,430評論 3 392
  • 文/潘曉璐 我一進店門囚痴,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人审葬,你說我怎么就攤上這事深滚。” “怎么了涣觉?”我有些...
    開封第一講書人閱讀 162,764評論 0 353
  • 文/不壞的土叔 我叫張陵痴荐,是天一觀的道長。 經常有香客問我官册,道長生兆,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,193評論 1 292
  • 正文 為了忘掉前任膝宁,我火速辦了婚禮鸦难,結果婚禮上,老公的妹妹穿的比我還像新娘员淫。我一直安慰自己合蔽,他們只是感情好,可當我...
    茶點故事閱讀 67,216評論 6 388
  • 文/花漫 我一把揭開白布介返。 她就那樣靜靜地躺著拴事,像睡著了一般。 火紅的嫁衣襯著肌膚如雪映皆。 梳的紋絲不亂的頭發(fā)上挤聘,一...
    開封第一講書人閱讀 51,182評論 1 299
  • 那天,我揣著相機與錄音捅彻,去河邊找鬼组去。 笑死,一個胖子當著我的面吹牛步淹,可吹牛的內容都是我干的从隆。 我是一名探鬼主播诚撵,決...
    沈念sama閱讀 40,063評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼键闺!你這毒婦竟也來了寿烟?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 38,917評論 0 274
  • 序言:老撾萬榮一對情侶失蹤辛燥,失蹤者是張志新(化名)和其女友劉穎筛武,沒想到半個月后,有當地人在樹林里發(fā)現了一具尸體挎塌,經...
    沈念sama閱讀 45,329評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡徘六,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,543評論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現自己被綠了榴都。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片待锈。...
    茶點故事閱讀 39,722評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖嘴高,靈堂內的尸體忽然破棺而出竿音,到底是詐尸還是另有隱情,我是刑警寧澤拴驮,帶...
    沈念sama閱讀 35,425評論 5 343
  • 正文 年R本政府宣布春瞬,位于F島的核電站,受9級特大地震影響套啤,放射性物質發(fā)生泄漏快鱼。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,019評論 3 326
  • 文/蒙蒙 一纲岭、第九天 我趴在偏房一處隱蔽的房頂上張望抹竹。 院中可真熱鬧,春花似錦止潮、人聲如沸窃判。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,671評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽袄琳。三九已至,卻和暖如春燃乍,著一層夾襖步出監(jiān)牢的瞬間唆樊,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,825評論 1 269
  • 我被黑心中介騙來泰國打工刻蟹, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留逗旁,地道東北人。 一個月前我還...
    沈念sama閱讀 47,729評論 2 368
  • 正文 我出身青樓舆瘪,卻偏偏與公主長得像片效,于是被迫代替她去往敵國和親红伦。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,614評論 2 353

推薦閱讀更多精彩內容