JS閉包到底是什么

這篇文章主要講解了“JS閉包到底是什么”,文中的講解內(nèi)容簡單清晰,易于學(xué)習(xí)與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學(xué)習(xí)“JS閉包到底是什么”吧!

創(chuàng)新互聯(lián)公司一直秉承“誠信做人,踏實做事”的原則,不欺瞞客戶,是我們最起碼的底線! 以服務(wù)為基礎(chǔ),以質(zhì)量求生存,以技術(shù)求發(fā)展,成交一個客戶多一個朋友!為您提供網(wǎng)站建設(shè)、成都網(wǎng)站制作、成都網(wǎng)頁設(shè)計、小程序設(shè)計、成都網(wǎng)站開發(fā)、成都網(wǎng)站制作、成都軟件開發(fā)、重慶APP軟件開發(fā)是成都本地專業(yè)的網(wǎng)站建設(shè)和網(wǎng)站設(shè)計公司,等你一起來見證!

  

在JavaScript這門語言中,閉包是它的核心基礎(chǔ)之一,可以說是一個特色了,但是很多從事前端工作的程序員并沒有真正的理解它!

閉包有多重要?如果你是初入前端的朋友,我可以肯定得告訴你,前端面試,必問閉包。面試官們常常用對閉包的了解程度來判定面試者的基礎(chǔ)水平,保守估計,10個前端面試者,至少5個都死在閉包上。

通過本文講解,希望你可以重新認(rèn)識一下閉包!

函數(shù)調(diào)用時發(fā)生了什么?

為了理解閉包,首先我們需要完全理解 JavaScript 到底是如何工作的!

那么函數(shù)調(diào)用是會發(fā)生什么呢?

當(dāng)瀏覽器在解析 JS代碼的時候,會進(jìn)行一個預(yù)解析的操作,會有一個js解析器,里面會執(zhí)行其中的兩步操作:

1、預(yù)解析,找一些東西(var function 參數(shù));

2、逐行去解讀代碼。

當(dāng)解析器解讀函數(shù)調(diào)用時,會將整個函數(shù)執(zhí)行一個入棧操作,并為函數(shù)創(chuàng)建一個新的執(zhí)行上下文。函數(shù)內(nèi)部可以看作是一個小的區(qū)域,它有它自己的作用域和執(zhí)行線程,也要逐行解讀。當(dāng)函數(shù)顯式返回(到達(dá)return語句)或隱式返回(默認(rèn)情況下函數(shù)返回undefined)時,函數(shù)將出棧,其執(zhí)行上下文也將被銷毀。

閉包是什么鬼?

我們先來看下這段代碼:

let name = "John"  function greet() {   const greeting = "Hi"    function printHi() {     console.log(greeting + ' ' + name)   }   printHi() }  name = "Jane"  greet() // "Hi Jane"

我們發(fā)現(xiàn),子函數(shù) printHi 可以訪問全局作用域和其父函數(shù) greet 的局部作用域。

注意,我們實際上可以訪問函數(shù)執(zhí)行期間可用的“新”數(shù)據(jù),而不是聲明。這就是詞法作用域在 JavaScript 中的工作方式。

但是如果我們返回一個函數(shù),而不是僅僅在外部函數(shù)體中調(diào)用它,會發(fā)生什么呢?

看好了,奇跡出現(xiàn)了!

從一個函數(shù)中返回的函數(shù)不僅僅是一個簡單的函數(shù)定義,它是這個定義加上它可以訪問并需要執(zhí)行的變量,這些變量存儲在它附帶的詞法作用域中。

我們剛剛描述的就是閉包。從形式上講,閉包是一個「即使在詞法范圍之外調(diào)用,仍可以記住它的詞法范圍」的函數(shù)。

function creator(num) {   return function() {     num = num * 2     console.log(num)   } }  const double = creator(5) double() //10 double() //20  const double2 = creator(7) double2() // 14 double2() //28  double() // 40

正如我們在上面的代碼片段中看到的,每當(dāng)我們調(diào)用 double  時,它都會更新存儲在其詞法作用域中的同一個變量(來自其父函數(shù)的num),從技術(shù)上講,這是函數(shù)所具有的隱藏 [[scope]] 屬性。

如果你想知道閉包到底有什么用,請繼續(xù)看下面的示例。

模塊封裝

閉包允許我們保護(hù)或隱藏某些信息。[[scope]]  是一個隱藏的屬性,所以我們不能像使用標(biāo)準(zhǔn)對象那樣訪問和更新它。還有一點很重要,我們可以返回一組存儲在對象上的函數(shù),它們都是閉包。

在下面的代碼片段中,我們利用了所謂的IIFE(立即執(zhí)行函數(shù)),它允許我們消除調(diào)用外部函數(shù)的中間步驟,就像我們在賦值時直接調(diào)用它一樣。

const myModule  = (function(){   const apiKey = "123456789"    return {     displayKey() {       console.log(apiKey)     }   }  })()  myModule.displayKey() // "123456789"

如果我們將這個模塊 export 出去, 提供給其他人使用,我們?yōu)樗麥?zhǔn)備的 API 不允許他更改  apiKey,這就做到了只讀屬性,除了在源代碼中重寫它之外,調(diào)用方不可能更改它。

緩存和記憶化

假設(shè)您想創(chuàng)建一個簡單的ID生成器。為了確??偸欠祷乇壬弦粋€高的數(shù)字,也可以使用閉包。我們將緩存當(dāng)前變量中最高的 ID 值。

const newID = (function() {   let current = 0   return function() {     return ++current   } })()  newID() // 1 newID() // 2

當(dāng)我們的算法時間復(fù)雜度很高時,這種緩存方式就非常有用,我們可以將部分結(jié)果存儲在緩存中,當(dāng)我們使用更高的數(shù)字進(jìn)行計算時,我們可以使用緩存中的數(shù)據(jù)作為基礎(chǔ)。這個過程叫做記憶化。一個最好的例子就是處理處理遞歸問題,比如斐波那契序列。

const factorialMemo = (function() {   const cache = {}   return function factorial(n) {     if(n === 1 || n === 0) {       return 1     } else if (cache[n]) {       return cache[n]     } else {       cache[n] = n * factorial(n-1)       return cache[n]     }   } })()   factorialMemo(5) //120 // cache object looks like {'2': 2, '3' : 6, '4' : 24, '5' : 120} factorialMemo(6) // 6 * cached 120

感謝各位的閱讀,以上就是“JS閉包到底是什么”的內(nèi)容了,經(jīng)過本文的學(xué)習(xí)后,相信大家對JS閉包到底是什么這一問題有了更深刻的體會,具體使用情況還需要大家實踐驗證。這里是創(chuàng)新互聯(lián),小編將為大家推送更多相關(guān)知識點的文章,歡迎關(guān)注!

分享標(biāo)題:JS閉包到底是什么
地址分享:http://bm7419.com/article30/jddgso.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供動態(tài)網(wǎng)站、、企業(yè)網(wǎng)站制作、網(wǎng)站策劃、建站公司、響應(yīng)式網(wǎng)站

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)

搜索引擎優(yōu)化