自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

Web前端:征服 JavaScript 面試之什么是閉包?

開發(fā) 前端
在我面試時(shí)問出的一系列問題里,閉包通常是我問的第一個(gè)或最后一個(gè)問題。坦白地說,如果你連閉包也弄不明白,你是不會(huì)在 JavaScript 的道路上走多遠(yuǎn)的。

 前言

在我面試時(shí)問出的一系列問題里,閉包通常是我問的***個(gè)或***一個(gè)問題。坦白地說,如果你連閉包也弄不明白,你是不會(huì)在 JavaScript 的道路上走多遠(yuǎn)的。

你別東張西望,說的就是你。你真的理解如何構(gòu)建一個(gè)嚴(yán)謹(jǐn)?shù)?JavaScript 應(yīng)用?你真的理解代碼背后發(fā)生的事情或者說一個(gè)應(yīng)用程序是如何工作的?我表示懷疑。如果連個(gè)閉包問題都搞不清的話,真是有點(diǎn)夠嗆。

[[270040]]

你不僅僅應(yīng)該了解閉包的機(jī)制,更應(yīng)該了解閉包為什么很重要,以及能夠很容易地回答出閉包的幾種可能的應(yīng)用場景。

閉包在 JavaScript 中常用來實(shí)現(xiàn)對象數(shù)據(jù)的私有,在事件處理和回調(diào)函數(shù)中也常常會(huì)用到它,此外還有偏函數(shù)應(yīng)用(partial applications)和柯里化(currying),以及其他函數(shù)式編程模式。

我不在乎面試者是否知道“closure”這個(gè)單詞或者它的專業(yè)定義。我只想弄清他們是否理解基本原理。如果他們沒有,那么通常意味著這些面試者在構(gòu)建實(shí)際 JavaScript 應(yīng)用方面并沒有很多經(jīng)驗(yàn)。

如果你不能回答這個(gè)問題,你只是個(gè)初級(jí)開發(fā)者。不管你實(shí)際上已經(jīng)干這個(gè)多久了。

為了快速理解下面的內(nèi)容:你想一下能否舉出兩個(gè)閉包的通用場景?

什么是閉包?

簡言之,閉包是由函數(shù)引用其周邊狀態(tài)(詞法環(huán)境)綁在一起形成的(封裝)組合結(jié)構(gòu)。在 JavaScript 中,閉包在每個(gè)函數(shù)被創(chuàng)建時(shí)形成。

這是基本原理,但為什么我們關(guān)心這些?實(shí)際上,由于閉包與它的詞法環(huán)境綁在一起,因此閉包讓我們能夠從一個(gè)函數(shù)內(nèi)部訪問其外部函數(shù)的作用域。

要使用閉包,只需要簡單地將一個(gè)函數(shù)定義在另一個(gè)函數(shù)內(nèi)部,并將它暴露出來。要暴露一個(gè)函數(shù),可以將它返回或者傳給其他函數(shù)。

內(nèi)部函數(shù)將能夠訪問到外部函數(shù)作用域中的變量,即使外部函數(shù)已經(jīng)執(zhí)行完畢。

閉包使用的例子

閉包的用途之一是實(shí)現(xiàn)對象的私有數(shù)據(jù)。數(shù)據(jù)私有是讓我們能夠面向接口編程而不是面向?qū)崿F(xiàn)編程的基礎(chǔ)。而面向接口編程是一個(gè)重要的概念,有助于我們創(chuàng)建更加健壯的軟件,因?yàn)閷?shí)現(xiàn)細(xì)節(jié)比接口約定相對來說更加容易被改變。

“面向接口編程,別面向?qū)崿F(xiàn)編程。” 設(shè)計(jì)模式:可復(fù)用面向?qū)ο筌浖囊?/p>

在 JavaScript 中,閉包是用來實(shí)現(xiàn)數(shù)據(jù)私有的原生機(jī)制。當(dāng)你使用閉包來實(shí)現(xiàn)數(shù)據(jù)私有時(shí),被封裝的變量只能在閉包容器函數(shù)作用域中使用。你無法繞過對象被授權(quán)的方法在外部訪問這些數(shù)據(jù)。在 JavaScript 中,任何定義在閉包作用域下的公開方法才可以訪問這些數(shù)據(jù)。例如:

  1. const getSecret = (secret) => { 
  2.  return { 
  3.  get: () => secret 
  4.  }; 
  5. }; 
  6. test('Closure for object privacy.', assert => { 
  7.  const msg = '.get() should have access to the closure.'
  8.  const expected = 1; 
  9.  const obj = getSecret(1); 
  10.  const actual = obj.get(); 
  11.  try { 
  12.  assert.ok(secret, 'This throws an error.'); 
  13.  } catch (e) { 
  14.  assert.ok(true, `The secret var is only available 
  15.  to privileged methods.`); 
  16.  } 
  17.  assert.equal(actual, expected, msg); 
  18.  assert.end(); 
  19. }); 

在上面的例子里,get() 方法定義在 getSecret() 作用域下,這讓它可以訪問任何 getSecret()中的變量,于是它就是一個(gè)被授權(quán)的方法。在這個(gè)例子里,它可以訪問參數(shù) secret。

對象不是唯一的產(chǎn)生私有數(shù)據(jù)的方式。閉包還可以被用來創(chuàng)建有狀態(tài)的函數(shù),這些函數(shù)的執(zhí)行過程可能由它們自身的內(nèi)部狀態(tài)所決定。例如:

  1. const secret = (msg) => () => msg; 
  2. // Secret - creates closures with secret messages. 
  3. // https://gist.github.com/ericelliott/f6a87bc41de31562d0f9 
  4. // https://jsbin.com/hitusu/edit?html,js,output 
  5. // secret(msg: String) => getSecret() => msg: String 
  6. const secret = (msg) => () => msg; 
  7. test('secret', assert => { 
  8.  const msg = 'secret() should return a function that returns the passed secret.'
  9.  const theSecret = 'Closures are easy.'
  10.  const mySecret = secret(theSecret); 
  11.  const actual = mySecret(); 
  12.  const expected = theSecret; 
  13.  assert.equal(actual, expected, msg); 
  14.  assert.end(); 
  15. }); 

在函數(shù)式編程中,閉包經(jīng)常用于偏函數(shù)應(yīng)用和柯里化。為了說明這個(gè),我們先定義一些概念:

函數(shù)應(yīng)用:一個(gè)過程,指將參數(shù)傳給一個(gè)函數(shù),并獲得它的返回值。

偏函數(shù)應(yīng)用:一個(gè)過程,它傳給某個(gè)函數(shù)其中一部分參數(shù),然后返回一個(gè)新的函數(shù),該函數(shù)等待接受后續(xù)參數(shù)。換句話說,偏函數(shù)應(yīng)用是一個(gè)函數(shù),它接受另一個(gè)函數(shù)為參數(shù),這個(gè)作為參數(shù)的函數(shù)本身接受多個(gè)參數(shù),它返回一個(gè)函數(shù),這個(gè)函數(shù)與它的參數(shù)函數(shù)相比,接受更少的參數(shù)。偏函數(shù)應(yīng)用提前賦予一部分參數(shù),而返回的函數(shù)則等待調(diào)用時(shí)傳入剩余的參數(shù)。

偏函數(shù)應(yīng)用通過閉包作用域來提前賦予參數(shù)。你可以實(shí)現(xiàn)一個(gè)通用的函數(shù)來賦予指定的函數(shù)部分參數(shù),它看起來如下:

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

如果你要更進(jìn)一步理解上面的形式,你可以看這里。

partialApply 接受一個(gè)多參數(shù)的函數(shù),以及一串我們想要提前賦給這個(gè)函數(shù)的參數(shù),它返回一個(gè)新的函數(shù),這個(gè)函數(shù)將接受剩余的參數(shù)。

下面給一個(gè)例子來說明,假設(shè)你有一個(gè)函數(shù),求兩個(gè)數(shù)的和:

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

現(xiàn)在你想要得到一個(gè)函數(shù),它能夠?qū)θ魏蝹鹘o它的參數(shù)都加 10,我們可以將它命名為 add10()。add10(5) 的結(jié)果應(yīng)該是 15。我們的 partialApply() 函數(shù)可以做到這個(gè):

  1. const add10 = partialApply(add, 10); 
  2. add10(5); 

在這個(gè)例子里,參數(shù) 10 通過閉包作用域被提前賦予 add(),從而讓我們獲得 add10()。

現(xiàn)在讓我們看一下如何實(shí)現(xiàn) partialApply():

  1. // Generic Partial Application Function 
  2. // https://jsbin.com/biyupu/edit?html,js,output 
  3. // https://gist.github.com/ericelliott/f0a8fd662111ea2f569e 
  4. // partialApply(targetFunction: Function, ...fixedArgs: Any[]) => 
  5. // functionWithFewerParams(...remainingArgs: Any[]) 
  6. const partialApply = (fn, ...fixedArgs) => { 
  7.  return function (...remainingArgs) { 
  8.  return fn.apply(this, fixedArgs.concat(remainingArgs)); 
  9.  }; 
  10. }; 
  11. test('add10', assert => { 
  12.  const msg = 'partialApply() should partially apply functions' 
  13.  const add = (a, b) => a + b; 
  14.  const add10 = partialApply(add, 10); 
  15.  const actual = add10(5); 
  16.  const expected = 15; 
  17.  assert.equal(actual, expected, msg); 
  18. }); 

如你所見,它只是簡單地返回一個(gè)函數(shù),這個(gè)函數(shù)通過閉包訪問了傳給 partialApply() 函數(shù)的 fixedArgs 參數(shù)。

輪到你來試試了

你用閉包來做什么?如果你有最喜歡的應(yīng)用場景,舉一些例子,在評論中告訴我。

責(zé)任編輯:武曉燕 來源: 今日頭條
相關(guān)推薦

2021-06-04 07:04:29

閉包JavaScript函數(shù)

2021-01-13 11:25:12

JavaScript閉包函數(shù)

2019-11-07 21:51:18

閉包前端函數(shù)

2017-05-22 16:08:30

前端開發(fā)javascript閉包

2021-02-21 16:21:19

JavaScript閉包前端

2011-05-25 14:48:33

Javascript閉包

2020-10-14 15:15:28

JavaScript(

2022-01-18 08:16:52

Web 前端JavaScript

2011-08-03 08:59:46

JavaScript

2017-09-14 13:55:57

JavaScript

2016-09-14 09:20:05

JavaScript閉包Web

2009-07-24 17:30:37

Javascript閉

2021-03-01 09:39:34

閉包JavaScript開發(fā)

2017-02-08 10:54:38

JavaScriptVR世界

2012-11-29 10:09:23

Javascript閉包

2009-03-17 15:36:29

JavaScript循環(huán)事件

2010-06-23 10:24:42

Javascript閉

2016-09-18 20:53:16

JavaScript閉包前端

2025-03-18 12:00:00

閉包JavaScript前端

2021-03-06 09:18:51

JS閉包函數(shù)
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)