iT邦幫忙

2021 iThome 鐵人賽

DAY 11
0
Modern Web

每日挑戰,從Javascript面試題目了解一些你可能忽略的概念系列 第 11

每日挑戰,從Javascript面試題目了解一些你可能忽略的概念 - Day11

  • 分享至 

  • xImage
  •  
tags: ItIron2021 Javascript

前言

昨天我們簡單的帶過IIFE,今天的主題則比較刁鑽一些,會用到我們之前談過的許多觀念,也是很多面試者心目中的大魔王,但實際上並沒有這麼複雜! 我們馬上開始吧!

本日題目與解釋

請解釋什麼是閉包(closure)

防雷圖來囉~!

thinking-day11

沒錯,終究是逃不過這一關的! 我們昨天有稍微帶到這個關鍵字,這個觀念關係到js底層是如何運作的,但理解後其實也不是真這麼困難,若要用一句話來說的話,我會給出以下的解釋。

  • 閉包就是函數本身以及他所參照的環境(lexical environment)

也就是不僅是函數本身,函數本身參照外部參數的行為就會製造出閉包,看個常見的例子

function demo() {
  let name = 'Danny'
  return function() {
    console.log(`Hello, my name is ${name}`)
  }
}

const demoFunc = demo()
demoFunc() // Hello, my name is Danny

上述就是閉包的典型範例,很多人會說閉包就是function return function,但實際上只要你的函數有參照到外部的參數就會形成閉包,例如這樣的做法也會產生一個閉包

let b = 5

function add(a) {
  return a + b
}

閉包與一般函數的差別在於,一般函數中的變數在執行後就會從stack memory中消失,但由於閉包會需要不斷的參照外在環境的參數(以上方的例子來說就是b),他需要把那個參照的變數存在更長久保存的heap memory中不斷地引用,直到未來被js本身的垃圾回收機制處理掉。

既然閉包使用這麼麻煩,我們會什麼會需要閉包呢?

很好的問題,就像昨天提過的,遇到這樣的定義問題時,知道它是什麼遠遠不夠,最好是能給出一些為什麼需要它的理由或是一些實際的範例。js其實在很多你平常的使用中就有不斷用到閉包的概念,只是你沒有注意到而已,其中最主要的優勢為

  • 資料封裝(Data encapsulation)

藉由閉包你可以將一些函數或是變數私有化,讓它變得無法被外在的環境影響,藉由在閉包內創造一個私有的state,你可以確保這個變數、函數不會被預期之外的程式碼操作。

當然實際上閉包還有一些眉眉角角,有興趣的朋友別忘了作進一步的搜尋! 很多面試題目也經常會用到閉包的概念,例如一個萬惡的setTimeOut題目

for (var i = 1; i <= 5; i++) {
  setTimeout(()=> {
    console.log(i)
  }, 100)
}

最終的輸出結果是5個6,你也許知道把var改為let就可以輕鬆印出目標的1~5,但...實際上這就是善用閉包的特性才能達到的,同時參照外部環境的行為是基於scope的特性,這你知道嗎??

本日核心觀念與總結

核心觀念

閉包(closure)、scope

總結

  • 能簡單說明何謂閉包
  • 了解閉包的主要優點

本文章同步發布於個人部落格,有興趣的朋友也可以來逛逛~!


上一篇
每日挑戰,從Javascript面試題目了解一些你可能忽略的概念 - Day10
下一篇
每日挑戰,從Javascript面試題目了解一些你可能忽略的概念 - Day12
系列文
每日挑戰,從Javascript面試題目了解一些你可能忽略的概念30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

1 則留言

0
gior__ann
iT邦新手 2 級 ‧ 2021-10-06 13:56:10

想請問一下~ setTimeOut題目,它的運算過程? 因為不是很懂閉包?/images/emoticon/emoticon06.gif

var i; // 只知道 var i 應該是被提升到外面??
for (var i = 1; i <= 5; i++) {

   // 迴圈內不太了解 i 值的變化為甚麼直接跳到 i = 6 ??
  setTimeout(()=> {
    console.log(i)
  }, 100)
}

@gior_ann 這個範例中i為什麼會變為6與閉包並沒有太直接的相關,會變為6主要是因為js有個處理同步與非同步程式碼的流程造成了這樣的結果。簡單來說當console.log(i)要執行時,其實整個迴圈早就跑完了,跑完迴圈後的i就是6(i === 5的時候還是會進入迴圈,跑完後+1變成6)
至於為什麼迴圈會早就跑完呢? 你可以參考昨天的Day20文章提供的內容與影片,如果看完還是很困惑歡迎你再繼續詢問囉!

gior__ann iT邦新手 2 級 ‧ 2021-10-07 09:41:29 檢舉

哈哈 ~ 謝謝詳解
我再去看看day20 理解一下~

我要留言

立即登入留言