掌握Javascript面试:什么是闭包?

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

在JavaScript的面试中我通常将这个问题放在第一个或者最后一个问题。坦白地说,如果你没有深入的学习闭包你的JavaScript不可能有很深的造诣。

你可能JavaScript稍好点儿,但你真的理解如何构建一个好的JavaScript应用吗?你真的理解什么正在运行,或者应用如何工作的吗?我对此表示怀疑。不知道这个问题的答案在面试的过程中是一个危险的信号。

你不仅应该知道闭包的工作机制是什么,你还应该知道他为什么发生,并且你应该很轻松的回答几种常用的闭包用例。

闭包常用在JavaScript对象的数据私有化,事件句柄,回调函数,和在局部应用,柯里化,以及其他功能的变成形式。

我不在乎面试候选人是否知道‘closure’这个词语或者技术定义。我想要弄明白的是他们是否理解基本的运行机制。如果他们不知道,显而易见这些面试候选者并没有大量的实际JavaScript应用开发经验。

“如果你不能回答这个问题,你就是一个初级开发人员。我不管你工作了几年。”

这听起来意味着什么,但实际上并不是。我的意思是大多数称职的面试官会问你什么是闭包,并且在大多数时候你回答错误将失去这份工作。如果你足够幸运的话,你将得到一个offer,他们将给你一个初级开发人员的工资而不是一个高级的开发人员。

准备好快速跟进:“你能说出两种常用的闭包吗?”

什么是闭包?

闭包就是一个函数(封闭的)的集合引用的环境(词法环境)状态。换句话说,闭包有能力从一个内部函数访问外部函数的作用域。在JavaScript中,在函数被创建时,每次一个函数被创建闭包也被创建。

用一个闭包,只需在一个函数内部定义一个函数,暴露这个内部的函数,然后返回这个函数,或者把它传递给另一个函数。内部的函数将有能力访问外部函数作用域的变量,即使外部的函数有返回值

使用闭包(实例)

刨除其他的,闭包通常用于对象的数据私有化。数据的私有化是帮助我们开发接口的一个重要的属性,而不是实现(应用的开发的细节实现)。他是一个帮助我们开发一个稳健的软件的重要概念,因为实现细节往往比接口约定更容易被打破。

“程序之于接口,而不是实现”

设计模式:可重用的面向对象软件的元素

在javascript中闭包是的主要机制就是被用来实现数据的私有化。当你用笔包进行数据的私有化,所包含的变量仅被包含在在外部的函数作用域内。除了通过对象的特权方法外,你将不能从外部范围获取数据。在闭包的范围内定义的任何公开方法都是特权的。例如:

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()’范围内定义的,这使得它可以从‘getsecret()’访问任何变量,并使它 成为一个特权方法。

使对象的数据私有化并不是闭包的唯一用途。它也可以用来创建有状态的函数,这些函数的返回值可能受他们内部状态的影响。示例如下:

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();
});

在函数式编程中,闭包常常被用在局部应用&柯里化编程,这里需要明白一些定义:
应用程序:应用一个函数的参数已返回一个值得过程
部分应用:函数应用他的部分参数的过程,这个部分被应用的函数稍后被用来获得返回值。换句话来说,一个函数转变一个多参数的函数,并利用它的返回一个少参数的函数。

部分应用利用闭包的作用域来处理参数对象,你可以写一个泛型函数部分的将参数应用于目标函数,下面有一个示例:

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

它将接受一个带有任意数量参数的函数,接下来我们想要部分的应用函数的参数然后返回一个带有剩余参数的函数。

下面一个例子,一个求两个数字和的函数:

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

现在你想要一个实现对任意数字都加10的函数,我们命名它为‘add10()’。‘add10(5)’的结果应该是‘15’,我们顶一个‘partialAply()’的函数,如下:

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

在这个例子中,参数‘10’变成了一个固定的参数被保存在‘add10()’的闭包作用域中。
下面是‘partialApply()’的实现代码:

// 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);
});

正如我们从上面的示例中看到的,这个简单的返回函数可以访问‘fixArgs’参数,这个参数是从‘partialApply()’中传入的。

未经许可不得转载!

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,907评论 6 506
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,987评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,298评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,586评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,633评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,488评论 1 302
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,275评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,176评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,619评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,819评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,932评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,655评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,265评论 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,871评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,994评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,095评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,884评论 2 354

推荐阅读更多精彩内容