掌握J(rèn)avascript面試:什么是閉包?

文章來源于:https://medium.com/javascript-scene/master-the-javascript-interview-what-is-a-closure-b2f0d2152b36

在JavaScript的面試中我通常將這個問題放在第一個或者最后一個問題奶躯。坦白地說璧榄,如果你沒有深入的學(xué)習(xí)閉包你的JavaScript不可能有很深的造詣。

你可能JavaScript稍好點兒吧雹,但你真的理解如何構(gòu)建一個好的JavaScript應(yīng)用嗎?你真的理解什么正在運行骨杂,或者應(yīng)用如何工作的嗎?我對此表示懷疑雄卷。不知道這個問題的答案在面試的過程中是一個危險的信號搓蚪。

你不僅應(yīng)該知道閉包的工作機制是什么,你還應(yīng)該知道他為什么發(fā)生丁鹉,并且你應(yīng)該很輕松的回答幾種常用的閉包用例妒潭。

閉包常用在JavaScript對象的數(shù)據(jù)私有化,事件句柄揣钦,回調(diào)函數(shù)雳灾,和在局部應(yīng)用,柯里化冯凹,以及其他功能的變成形式谎亩。

我不在乎面試候選人是否知道‘closure’這個詞語或者技術(shù)定義。我想要弄明白的是他們是否理解基本的運行機制。如果他們不知道匈庭,顯而易見這些面試候選者并沒有大量的實際JavaScript應(yīng)用開發(fā)經(jīng)驗夫凸。

“如果你不能回答這個問題,你就是一個初級開發(fā)人員阱持。我不管你工作了幾年夭拌。”

這聽起來意味著什么衷咽,但實際上并不是鸽扁。我的意思是大多數(shù)稱職的面試官會問你什么是閉包,并且在大多數(shù)時候你回答錯誤將失去這份工作兵罢。如果你足夠幸運的話献烦,你將得到一個offer,他們將給你一個初級開發(fā)人員的工資而不是一個高級的開發(fā)人員卖词。

準(zhǔn)備好快速跟進(jìn):“你能說出兩種常用的閉包嗎巩那?”

什么是閉包?

閉包就是一個函數(shù)(封閉的)的集合引用的環(huán)境(詞法環(huán)境)狀態(tài)此蜈。換句話說即横,閉包有能力從一個內(nèi)部函數(shù)訪問外部函數(shù)的作用域。在JavaScript中裆赵,在函數(shù)被創(chuàng)建時东囚,每次一個函數(shù)被創(chuàng)建閉包也被創(chuàng)建。

用一個閉包战授,只需在一個函數(shù)內(nèi)部定義一個函數(shù)页藻,暴露這個內(nèi)部的函數(shù),然后返回這個函數(shù)植兰,或者把它傳遞給另一個函數(shù)份帐。內(nèi)部的函數(shù)將有能力訪問外部函數(shù)作用域的變量,即使外部的函數(shù)有返回值

使用閉包(實例)

刨除其他的楣导,閉包通常用于對象的數(shù)據(jù)私有化废境。數(shù)據(jù)的私有化是幫助我們開發(fā)接口的一個重要的屬性,而不是實現(xiàn)(應(yīng)用的開發(fā)的細(xì)節(jié)實現(xiàn))筒繁。他是一個幫助我們開發(fā)一個穩(wěn)健的軟件的重要概念噩凹,因為實現(xiàn)細(xì)節(jié)往往比接口約定更容易被打破。

“程序之于接口毡咏,而不是實現(xiàn)”

設(shè)計模式:可重用的面向?qū)ο筌浖脑?/a>

在javascript中閉包是的主要機制就是被用來實現(xiàn)數(shù)據(jù)的私有化驮宴。當(dāng)你用筆包進(jìn)行數(shù)據(jù)的私有化,所包含的變量僅被包含在在外部的函數(shù)作用域內(nèi)血当。除了通過對象的特權(quán)方法外幻赚,你將不能從外部范圍獲取數(shù)據(jù)禀忆。在閉包的范圍內(nèi)定義的任何公開方法都是特權(quán)的。例如:

const getSecret = (secret) => {
  return {
    get: () => secret
  };
};

test('Closure for object privacy.', assert => {
  const msg = '.get() should have access to the closure.';
  const expected = 1;
  const obj = getSecret(1);

  const actual = obj.get();

  try {
    assert.ok(secret, 'This throws an error.');
  } catch (e) {
    assert.ok(true, `The secret var is only available
      to privileged methods.`);
  }

  assert.equal(actual, expected, msg);
  assert.end();
});

在上面的例子中落恼,‘.get()’方法是在‘getsecret()’范圍內(nèi)定義的箩退,這使得它可以從‘getsecret()’訪問任何變量,并使它 成為一個特權(quán)方法。

使對象的數(shù)據(jù)私有化并不是閉包的唯一用途佳谦。它也可以用來創(chuàng)建有狀態(tài)的函數(shù)戴涝,這些函數(shù)的返回值可能受他們內(nèi)部狀態(tài)的影響。示例如下:

const secret = msg => () => msg;

// Secret - creates closures with secret messages.
// https://gist.github.com/ericelliott/f6a87bc41de31562d0f9
// https://jsbin.com/hitusu/edit?html,js,output

// secret(msg: String) => getSecret() => msg: String
const secret = (msg) => () => msg;

test('secret', assert => {
  const msg = 'secret() should return a function that returns the passed secret.';

  const theSecret = 'Closures are easy.';
  const mySecret = secret(theSecret);

  const actual = mySecret();
  const expected = theSecret;

  assert.equal(actual, expected, msg);
  assert.end();
});

在函數(shù)式編程中钻蔑,閉包常常被用在局部應(yīng)用&柯里化編程,這里需要明白一些定義:
應(yīng)用程序:應(yīng)用一個函數(shù)的參數(shù)已返回一個值得過程
部分應(yīng)用:函數(shù)應(yīng)用他的部分參數(shù)的過程啥刻,這個部分被應(yīng)用的函數(shù)稍后被用來獲得返回值。換句話來說咪笑,一個函數(shù)轉(zhuǎn)變一個多參數(shù)的函數(shù)可帽,并利用它的返回一個少參數(shù)的函數(shù)。

部分應(yīng)用利用閉包的作用域來處理參數(shù)對象窗怒,你可以寫一個泛型函數(shù)部分的將參數(shù)應(yīng)用于目標(biāo)函數(shù)映跟,下面有一個示例:

partialApply(targetFunction: Function, ...fixedArgs: Any[]) =>
    functionWithFewerParams(...remainingArgs: Any[])

它將接受一個帶有任意數(shù)量參數(shù)的函數(shù),接下來我們想要部分的應(yīng)用函數(shù)的參數(shù)然后返回一個帶有剩余參數(shù)的函數(shù)扬虚。

下面一個例子努隙,一個求兩個數(shù)字和的函數(shù):

const add = (a, b) => a + b;

現(xiàn)在你想要一個實現(xiàn)對任意數(shù)字都加10的函數(shù),我們命名它為‘a(chǎn)dd10()’辜昵≥┠鳎‘a(chǎn)dd10(5)’的結(jié)果應(yīng)該是‘15’,我們頂一個‘partialAply()’的函數(shù),如下:

const add10 = partialApply(add, 10);
add10(5);

在這個例子中堪置,參數(shù)‘10’變成了一個固定的參數(shù)被保存在‘a(chǎn)dd10()’的閉包作用域中躬存。
下面是‘partialApply()’的實現(xiàn)代碼:

// Generic Partial Application Function
// https://jsbin.com/biyupu/edit?html,js,output
// https://gist.github.com/ericelliott/f0a8fd662111ea2f569e

// partialApply(targetFunction: Function, ...fixedArgs: Any[]) =>
//   functionWithFewerParams(...remainingArgs: Any[])
const partialApply = (fn, ...fixedArgs) => {
  return function (...remainingArgs) {
    return fn.apply(this, fixedArgs.concat(remainingArgs));
  };
};
test('add10', assert => {
  const msg = 'partialApply() should partially apply functions'
  const add = (a, b) => a + b;
  const add10 = partialApply(add, 10);
  const actual = add10(5);
  const expected = 15;

  assert.equal(actual, expected, msg);
});

正如我們從上面的示例中看到的,這個簡單的返回函數(shù)可以訪問‘fixArgs’參數(shù)舀锨,這個參數(shù)是從‘partialApply()’中傳入的优构。

未經(jīng)許可不得轉(zhuǎn)載!

  • 序言:七十年代末雁竞,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子拧额,更是在濱河造成了極大的恐慌碑诉,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,270評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件侥锦,死亡現(xiàn)場離奇詭異进栽,居然都是意外死亡,警方通過查閱死者的電腦和手機恭垦,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,489評論 3 395
  • 文/潘曉璐 我一進(jìn)店門快毛,熙熙樓的掌柜王于貴愁眉苦臉地迎上來格嗅,“玉大人,你說我怎么就攤上這事唠帝⊥鸵矗” “怎么了?”我有些...
    開封第一講書人閱讀 165,630評論 0 356
  • 文/不壞的土叔 我叫張陵襟衰,是天一觀的道長贴铜。 經(jīng)常有香客問我,道長瀑晒,這世上最難降的妖魔是什么绍坝? 我笑而不...
    開封第一講書人閱讀 58,906評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮苔悦,結(jié)果婚禮上轩褐,老公的妹妹穿的比我還像新娘。我一直安慰自己玖详,他們只是感情好把介,可當(dāng)我...
    茶點故事閱讀 67,928評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著竹宋,像睡著了一般劳澄。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上蜈七,一...
    開封第一講書人閱讀 51,718評論 1 305
  • 那天秒拔,我揣著相機與錄音,去河邊找鬼飒硅。 笑死砂缩,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的三娩。 我是一名探鬼主播庵芭,決...
    沈念sama閱讀 40,442評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼雀监!你這毒婦竟也來了双吆?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,345評論 0 276
  • 序言:老撾萬榮一對情侶失蹤会前,失蹤者是張志新(化名)和其女友劉穎好乐,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體瓦宜,經(jīng)...
    沈念sama閱讀 45,802評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡蔚万,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,984評論 3 337
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了临庇。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片反璃。...
    茶點故事閱讀 40,117評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡昵慌,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出淮蜈,到底是詐尸還是另有隱情斋攀,我是刑警寧澤,帶...
    沈念sama閱讀 35,810評論 5 346
  • 正文 年R本政府宣布礁芦,位于F島的核電站蜻韭,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏柿扣。R本人自食惡果不足惜肖方,卻給世界環(huán)境...
    茶點故事閱讀 41,462評論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望未状。 院中可真熱鬧俯画,春花似錦、人聲如沸司草。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,011評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽埋虹。三九已至猜憎,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間搔课,已是汗流浹背胰柑。 一陣腳步聲響...
    開封第一講書人閱讀 33,139評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留爬泥,地道東北人柬讨。 一個月前我還...
    沈念sama閱讀 48,377評論 3 373
  • 正文 我出身青樓,卻偏偏與公主長得像袍啡,于是被迫代替她去往敵國和親踩官。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,060評論 2 355

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