[{"data":1,"prerenderedAt":640},["ShallowReactive",2],{"\u002Fpost\u002Fabout-javascript-closure":3},{"id":4,"title":5,"body":6,"date":622,"description":12,"extension":623,"hidden":624,"image":625,"meta":626,"navigation":56,"path":627,"seo":628,"sitemap":629,"stem":633,"subtitle":634,"tags":635,"__hash__":639},"posts\u002Fpost\u002Fabout-javascript-closure.md","我以為的閉包不是我以為的閉包...",{"type":7,"value":8,"toc":616},"minimark",[9,13,132,233,236,239,244,251,254,341,346,349,432,446,498,505,508,511,533,536,539,542,545,552,555,558,567,571,612],[10,11,12],"p",{},"前幾天同事問我為什麼這段 code 要這樣寫？",[14,15,21],"pre",{"className":16,"code":17,"language":18,"meta":19,"style":20},"language-js shiki shiki-themes light-plus tokyo-night","import axios from 'axios'\n\n\u002F\u002F api.js\nfunction getList(params) {\n  return axios.post('\u002Fapi\u002FgetList', params)\n}\n","js","showLineNumbers","",[22,23,24,51,58,65,90,126],"code",{"__ignoreMap":20},[25,26,29,33,37,40,44,48],"span",{"class":27,"line":28},"line",1,[25,30,32],{"class":31},"swGrk","import",[25,34,36],{"class":35},"sTOFy"," axios",[25,38,39],{"class":31}," from",[25,41,43],{"class":42},"sq7Q2"," '",[25,45,47],{"class":46},"s58z3","axios",[25,49,50],{"class":42},"'\n",[25,52,54],{"class":27,"line":53},2,[25,55,57],{"emptyLinePlaceholder":56},true,"\n",[25,59,61],{"class":27,"line":60},3,[25,62,64],{"class":63},"shM36","\u002F\u002F api.js\n",[25,66,68,72,76,80,84,87],{"class":27,"line":67},4,[25,69,71],{"class":70},"s5MyL","function",[25,73,75],{"class":74},"sjNAT"," getList",[25,77,79],{"class":78},"sNwUV","(",[25,81,83],{"class":82},"s_ePm","params",[25,85,86],{"class":78},")",[25,88,89],{"class":78}," {\n",[25,91,93,97,100,104,107,109,112,115,117,120,123],{"class":27,"line":92},5,[25,94,96],{"class":95},"svvEX","  return",[25,98,36],{"class":99},"sJUHq",[25,101,103],{"class":102},"s6v6z",".",[25,105,106],{"class":74},"post",[25,108,79],{"class":78},[25,110,111],{"class":42},"'",[25,113,114],{"class":46},"\u002Fapi\u002FgetList",[25,116,111],{"class":42},[25,118,119],{"class":102},",",[25,121,122],{"class":99}," params",[25,124,125],{"class":78},")\n",[25,127,129],{"class":27,"line":128},6,[25,130,131],{"class":78},"}\n",[14,133,135],{"className":16,"code":134,"language":18,"meta":19,"style":20},"\u002F\u002F component\nimport { getList } from '@\u002Fapi'\n\nfunction getDataList() {\n  \u002F\u002F 傳入參數後拿API的資料的function\n  const params = {\n    ...  \u002F\u002F 包含一堆要送入的參數\n  }\n  return getList(params)\n}\n",[22,136,137,142,164,168,180,185,199,209,215,228],{"__ignoreMap":20},[25,138,139],{"class":27,"line":28},[25,140,141],{"class":63},"\u002F\u002F component\n",[25,143,144,146,149,152,155,157,159,162],{"class":27,"line":53},[25,145,32],{"class":31},[25,147,148],{"class":78}," { ",[25,150,151],{"class":35},"getList",[25,153,154],{"class":78}," }",[25,156,39],{"class":31},[25,158,43],{"class":42},[25,160,161],{"class":46},"@\u002Fapi",[25,163,50],{"class":42},[25,165,166],{"class":27,"line":60},[25,167,57],{"emptyLinePlaceholder":56},[25,169,170,172,175,178],{"class":27,"line":67},[25,171,71],{"class":70},[25,173,174],{"class":74}," getDataList",[25,176,177],{"class":78},"()",[25,179,89],{"class":78},[25,181,182],{"class":27,"line":92},[25,183,184],{"class":63},"  \u002F\u002F 傳入參數後拿API的資料的function\n",[25,186,187,191,194,197],{"class":27,"line":128},[25,188,190],{"class":189},"sucPa","  const",[25,192,122],{"class":193},"sq2Xa",[25,195,196],{"class":102}," =",[25,198,89],{"class":78},[25,200,202,206],{"class":27,"line":201},7,[25,203,205],{"class":204},"sk53b","    ...",[25,207,208],{"class":63},"  \u002F\u002F 包含一堆要送入的參數\n",[25,210,212],{"class":27,"line":211},8,[25,213,214],{"class":78},"  }\n",[25,216,218,220,222,224,226],{"class":27,"line":217},9,[25,219,96],{"class":95},[25,221,75],{"class":74},[25,223,79],{"class":78},[25,225,83],{"class":99},[25,227,125],{"class":78},[25,229,231],{"class":27,"line":230},10,[25,232,131],{"class":78},[10,234,235],{},"問我為什麼要這樣寫之後，跟他解釋後，",[10,237,238],{},"他問了這樣的問題：",[10,240,241],{},[22,242,243],{},"我以為你是要寫閉包",[10,245,246],{},[247,248],"img",{"alt":249,"src":250},"question","\u002Fimages\u002Fpost\u002Fabout-javascript-closure\u002Fquestion.webp",[10,252,253],{},"我心想這不是閉包啊，至少跟我認知的閉包定義不一樣，我問他閉包的定義：一個 function 內返回另一個 function 就是閉包不是嗎？因為之前只有看過 MDN 上的定義以及用法而已，於是我開始研究所謂閉包到底是什麼...",[14,255,257],{"className":16,"code":256,"language":18,"meta":19,"style":20},"\u002F\u002F 我認為的閉包\nfunction makeCounter() {\n  let count = 0\n\n  return function () {\n    return count++\n  }\n}\n\nlet counter = makeCounter()\n",[22,258,259,264,275,290,294,304,314,318,322,326],{"__ignoreMap":20},[25,260,261],{"class":27,"line":28},[25,262,263],{"class":63},"\u002F\u002F 我認為的閉包\n",[25,265,266,268,271,273],{"class":27,"line":53},[25,267,71],{"class":70},[25,269,270],{"class":74}," makeCounter",[25,272,177],{"class":78},[25,274,89],{"class":78},[25,276,277,280,284,286],{"class":27,"line":60},[25,278,279],{"class":189},"  let",[25,281,283],{"class":282},"sY6z7"," count",[25,285,196],{"class":102},[25,287,289],{"class":288},"sjYsg"," 0\n",[25,291,292],{"class":27,"line":67},[25,293,57],{"emptyLinePlaceholder":56},[25,295,296,298,301],{"class":27,"line":92},[25,297,96],{"class":95},[25,299,300],{"class":70}," function",[25,302,303],{"class":78}," () {\n",[25,305,306,309,311],{"class":27,"line":128},[25,307,308],{"class":95},"    return",[25,310,283],{"class":99},[25,312,313],{"class":102},"++\n",[25,315,316],{"class":27,"line":201},[25,317,214],{"class":78},[25,319,320],{"class":27,"line":211},[25,321,131],{"class":78},[25,323,324],{"class":27,"line":217},[25,325,57],{"emptyLinePlaceholder":56},[25,327,328,331,334,336,338],{"class":27,"line":230},[25,329,330],{"class":189},"let",[25,332,333],{"class":282}," counter",[25,335,196],{"class":102},[25,337,270],{"class":74},[25,339,340],{"class":78},"()\n",[342,343,345],"h2",{"id":344},"一個-function-內返回另一個-function-就是閉包","一個 function 內返回另一個 function 就是閉包?",[10,347,348],{},"首先我們可以先看 code 是返回 axios 的函式，而 axios 返回的是一個 Promise",[14,350,352],{"className":16,"code":134,"highlights":351,"language":18,"meta":19,"style":20},[217],[22,353,354,358,376,380,390,394,404,410,414,428],{"__ignoreMap":20},[25,355,356],{"class":27,"line":28},[25,357,141],{"class":63},[25,359,360,362,364,366,368,370,372,374],{"class":27,"line":53},[25,361,32],{"class":31},[25,363,148],{"class":78},[25,365,151],{"class":35},[25,367,154],{"class":78},[25,369,39],{"class":31},[25,371,43],{"class":42},[25,373,161],{"class":46},[25,375,50],{"class":42},[25,377,378],{"class":27,"line":60},[25,379,57],{"emptyLinePlaceholder":56},[25,381,382,384,386,388],{"class":27,"line":67},[25,383,71],{"class":70},[25,385,174],{"class":74},[25,387,177],{"class":78},[25,389,89],{"class":78},[25,391,392],{"class":27,"line":92},[25,393,184],{"class":63},[25,395,396,398,400,402],{"class":27,"line":128},[25,397,190],{"class":189},[25,399,122],{"class":193},[25,401,196],{"class":102},[25,403,89],{"class":78},[25,405,406,408],{"class":27,"line":201},[25,407,205],{"class":204},[25,409,208],{"class":63},[25,411,412],{"class":27,"line":211},[25,413,214],{"class":78},[25,415,418,420,422,424,426],{"class":416,"line":217},[27,417],"highlight",[25,419,96],{"class":95},[25,421,75],{"class":74},[25,423,79],{"class":78},[25,425,83],{"class":99},[25,427,125],{"class":78},[25,429,430],{"class":27,"line":230},[25,431,131],{"class":78},[10,433,434,441,442,445],{},[435,436,440],"a",{"href":437,"rel":438},"https:\u002F\u002Fdeveloper.mozilla.org\u002Fzh-TW\u002Fdocs\u002FWeb\u002FJavaScript\u002FReference\u002FGlobal_Objects\u002FPromise",[439],"nofollow","Promise"," ",[22,443,444],{},"物件"," 代表一個即將完成、或失敗的非同步操作，以及它所產生的值。 from MDN",[14,447,449],{"className":16,"code":448,"language":18,"meta":19,"style":20},"\u002F\u002F 驗證一下\ntypeof new Promise((resolve) => resolve('Hello')) \u002F\u002F 'object'\n",[22,450,451,456],{"__ignoreMap":20},[25,452,453],{"class":27,"line":28},[25,454,455],{"class":63},"\u002F\u002F 驗證一下\n",[25,457,458,462,465,469,472,475,477,480,483,485,487,490,492,495],{"class":27,"line":53},[25,459,461],{"class":460},"s00W4","typeof",[25,463,464],{"class":460}," new",[25,466,468],{"class":467},"sX0bS"," Promise",[25,470,471],{"class":78},"((",[25,473,474],{"class":82},"resolve",[25,476,86],{"class":78},[25,478,479],{"class":70}," =>",[25,481,482],{"class":74}," resolve",[25,484,79],{"class":78},[25,486,111],{"class":42},[25,488,489],{"class":46},"Hello",[25,491,111],{"class":42},[25,493,494],{"class":78},"))",[25,496,497],{"class":63}," \u002F\u002F 'object'\n",[10,499,500,501,504],{},"所以 ",[22,502,503],{},"getDataList"," 這個 function 返回的是一個 function 嗎？",[342,506,507],{"id":507},"怎麼解釋閉包",[10,509,510],{},"這兩篇解釋得蠻清楚的",[512,513,514,522],"ol",{},[515,516,517],"li",{},[435,518,521],{"href":519,"rel":520},"https:\u002F\u002Fblog.huli.tw\u002F2018\u002F12\u002F08\u002Fjavascript-closure\u002F#%E6%89%80%E6%9C%89%E7%9A%84%E5%87%BD%E5%BC%8F%E9%83%BD%E6%98%AF%E9%96%89%E5%8C%85",[439],"所有的函式都是閉包",[515,523,524,528,529],{},[435,525,526],{"href":526,"rel":527},"https:\u002F\u002Fzh.javascript.info\u002Fclosure#la-ji-shou-ji",[439]," 往上滑一點就能看到\n",[247,530],{"alt":531,"src":532},"closure","\u002Fimages\u002Fpost\u002Fabout-javascript-closure\u002Fclosure.webp",[10,534,535],{},"闭包 是指一个函数可以记住其外部变量并可以访问这些变量。在某些编程语言中，这是不可能的，或者应该以一种特殊的方式编写函数来实现。但如上所述，在 JavaScript 中，所有函数都是天生闭包的（只有一个例外，将在 \"new Function\" 语法 中讲到）。",[10,537,538],{},"也就是说：JavaScript 中的函数会自动通过隐藏的 [[Environment]] 属性记住创建它们的位置，所以它们都可以访问外部变量。",[10,540,541],{},"在面试时，前端开发者通常会被问到“什么是闭包？”，正确的回答应该是闭包的定义，并解释清楚为什么 JavaScript 中的所有函数都是闭包的，以及可能的关于 [[Environment]] 属性和词法环境原理的技术细节。",[342,543,544],{"id":544},"結論",[10,546,547,548,551],{},"嚴格來說，",[22,549,550],{},"一個 function 內返回另一個 function 就是閉包","，這句話一點也沒錯，因為\"所有的函式都是閉包\"。但如果面試官問：請解釋一下閉包，這樣的回答是會被打槍並且被洗臉。也是藉由這次的經驗我才完全釐清之前對於閉包的誤解，所以標題才會是\"我以為的閉包不是我以為的閉包\"。",[10,553,554],{},"本篇並沒有打算討論何為閉包或閉包的定義，因為網路上已經有一堆優秀的文章解釋了，主要打這篇文章是為了讓我對於這次學習有個總結，以及附上參考連結讓我以後複習有個參照。",[10,556,557],{},"所以你也以為閉包是哪種呢？",[512,559,560,562,565],{},[515,561,550],{},[515,563,564],{},"閉包（Closure）是函式以及該函式被宣告時所在的作用域環境（lexical environment）的組合。 - from MDN",[515,566,521],{},[342,568,570],{"id":569},"ref","Ref",[572,573,574,584,591,598,605],"ul",{},[515,575,576,441,579],{},[22,577,578],{},"MDN",[435,580,583],{"href":581,"rel":582},"https:\u002F\u002Fdeveloper.mozilla.org\u002Fzh-TW\u002Fdocs\u002FWeb\u002FJavaScript\u002FClosures",[439],"閉包",[515,585,586],{},[435,587,590],{"href":588,"rel":589},"https:\u002F\u002Fzh.javascript.info\u002Fclosure",[439],"变量作用域，闭包",[515,592,593],{},[435,594,597],{"href":595,"rel":596},"https:\u002F\u002Fblog.huli.tw\u002F2018\u002F12\u002F08\u002Fjavascript-closure\u002F",[439],"所有的函式都是閉包：談 JS 中的作用域與 Closure",[515,599,600],{},[435,601,604],{"href":602,"rel":603},"https:\u002F\u002Fwww.cnblogs.com\u002Fwangfupeng1988\u002Fp\u002F3977924.html",[439],"深入理解 javascript 原型和闭包",[515,606,607],{},[435,608,611],{"href":609,"rel":610},"https:\u002F\u002Fengineering.cerner.com\u002Fblog\u002Fclosures-and-currying-in-javascript\u002F",[439],"Closures & Currying in JavaScript",[613,614,615],"style",{},"html pre.shiki code .swGrk, html code.shiki .swGrk{--shiki-default:#AF00DB;--shiki-dark:#7DCFFF}html pre.shiki code .sTOFy, html code.shiki .sTOFy{--shiki-default:#001080;--shiki-dark:#0DB9D7}html pre.shiki code .sq7Q2, html code.shiki .sq7Q2{--shiki-default:#A31515;--shiki-dark:#89DDFF}html pre.shiki code .s58z3, html code.shiki .s58z3{--shiki-default:#A31515;--shiki-dark:#9ECE6A}html pre.shiki code .shM36, html code.shiki .shM36{--shiki-default:#008000;--shiki-default-font-style:inherit;--shiki-dark:#51597D;--shiki-dark-font-style:italic}html pre.shiki code .s5MyL, html code.shiki .s5MyL{--shiki-default:#0000FF;--shiki-dark:#BB9AF7}html pre.shiki code .sjNAT, html code.shiki .sjNAT{--shiki-default:#795E26;--shiki-dark:#7AA2F7}html pre.shiki code .sNwUV, html code.shiki .sNwUV{--shiki-default:#000000;--shiki-dark:#9ABDF5}html pre.shiki code .s_ePm, html code.shiki .s_ePm{--shiki-default:#001080;--shiki-dark:#E0AF68}html pre.shiki code .svvEX, html code.shiki .svvEX{--shiki-default:#AF00DB;--shiki-default-font-style:inherit;--shiki-dark:#BB9AF7;--shiki-dark-font-style:italic}html pre.shiki code .sJUHq, html code.shiki .sJUHq{--shiki-default:#001080;--shiki-dark:#C0CAF5}html pre.shiki code .s6v6z, html code.shiki .s6v6z{--shiki-default:#000000;--shiki-dark:#89DDFF}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sucPa, html code.shiki .sucPa{--shiki-default:#0000FF;--shiki-default-font-style:inherit;--shiki-dark:#9D7CD8;--shiki-dark-font-style:italic}html pre.shiki code .sq2Xa, html code.shiki .sq2Xa{--shiki-default:#0070C1;--shiki-dark:#BB9AF7}html pre.shiki code .sk53b, html code.shiki .sk53b{--shiki-default:#000000;--shiki-default-font-weight:inherit;--shiki-dark:#F7768E;--shiki-dark-font-weight:bold}html pre.shiki code .sY6z7, html code.shiki .sY6z7{--shiki-default:#001080;--shiki-dark:#BB9AF7}html pre.shiki code .sjYsg, html code.shiki .sjYsg{--shiki-default:#098658;--shiki-dark:#FF9E64}html pre.shiki code .s00W4, html code.shiki .s00W4{--shiki-default:#0000FF;--shiki-dark:#89DDFF}html pre.shiki code .sX0bS, html code.shiki .sX0bS{--shiki-default:#267F99;--shiki-dark:#0DB9D7}",{"title":20,"searchDepth":53,"depth":53,"links":617},[618,619,620,621],{"id":344,"depth":53,"text":345},{"id":507,"depth":53,"text":507},{"id":544,"depth":53,"text":544},{"id":569,"depth":53,"text":570},"2023-06-15","md",false,"\u002Fimages\u002Fpost\u002Fabout-javascript-closure\u002Fpost.webp",{},"\u002Fpost\u002Fabout-javascript-closure",{"title":5,"description":12},{"loc":627,"images":630},[631,632],{"loc":250},{"loc":532},"post\u002Fabout-javascript-closure","面試官:請解釋一下閉包",[531,636,583,637,638],"javascript closure","我以為的閉包不是我以為的閉包","面試閉包","63uJzELpDecfyw0KdY7IhXBQfv4Cwj5b9P9cX2yEIlM",1791370767063]