「艾草艾草,你在做什麽?」
艾草:「没特别做什麽呀!」
「艾草艾草,我问你喔!」
艾草:「嗯嗯,问呀,但为什麽都要叫我名字两次呀?」
「透过两次的呼叫希望可以唤醒存在你心中的真善美,能使你成为更棒的存在!」
艾草:「??」
「上次在哪本魔法书看到的呀,好像某个术式要呼叫两次什麽的,实验一下!」
艾草:「啊,你说的应该是闭包吧?这个术式比较复杂,再陪你复习一次原理吧!」
以下引用至 MDN:
闭包(Closure)是函式以及该函式被宣告时所在的作用域环境(lexical environment)的组合。
这样可能不理解,来看一段程序码:
像这样函式内 return
函式,且内层函式内并没有 textContent
变数,需要透过范围链找到外层的 textContent
变数来使用,就称为闭包。
function outer(text) {
let textContent = text;
return function inner(name) {
console.log(`${textContent},${name}`); //"Hello,艾草"
};
}
闭包的呼叫要使用两个小括号,只使用一个小括号时,会印出整个内层函式,第二个小括号会呼叫被 return
的函式,底下分别为使用一个及两个小括号呼叫的印出结果:
一个小括号:
outer('Hello');
印出结果:
两个小括号:
outer('Hello')('艾草');
印出结果:
接下来,闭包还可以这样使用:
将变数赋予值为外层函式後,再透过变数呼叫内层函式,一样可以成功印出。
function outer(text) {
let textContent = text;
return function inner(name) {
console.log(`${textContent},${name}`); //"Hello,艾草"
};
}
let sayHello = outer('Hello');
sayHello('艾草');
为什麽内层函式可以持续取到外层函式的变数呢?
首先,传值、传参考文章内有提到:每宣告一个变数,都会有相对应的记忆体空间存放变数。
而每个执行环境都会有对应的记忆体空间存放变数、函式,所以当我们执行到程序码 let sayHello = outer('Hello')
时会跑去建立函式 outer
的执行环境,而执行到 let textContent = text
时,该执行环境内会产生记忆体空间来存放 textContent
变数与其值。
执行堆叠会如下图:
接下来回到全域执行环境执行到 sayHello('艾草')
时,会进行以下几个步骤:
outer
会离开执行环境sayHello()
, sayHello()
会指向函式 inner
inner
的执行环境,并於记忆体空间放置参数 name
inner
会需要参照外部函式 outer
的变数 textContent
而执行环境为了参考到外部变数 textContent
会将外部变数包覆起来,而这就是闭包。
JavaScript 会保留我们需要透过范围链参照的外部变数,即使该变数所在执行环境已离开执行堆叠。
JavaScript 全攻略:克服 JS 的奇怪部分(Udemy)
JavaScript 核心篇(六角学院)
https://developer.mozilla.org/zh-TW/docs/Web/JavaScript/Closures
<<: DAY24:Broadcast receiver之简介
D: cd pydata call C:\ProgramData\Anaconda3\Scripts...
Ruby是直译语言 程序码要能让电脑读懂,一定会有一个转译过程。 编译(Compiled langu...
从开始写文至今已经介绍过 HDMI、色差、SCART 和 S-Video 等 4 种端子了、但在序文...
从资源配置的角度思考 产品经理不一定有人事决定权,但是可以从资源的角度给予建议 这个是一个特别的经历...
当在公司历经了三年左右的时间,若能在前面文章的概念中不断落实与反覆演练,加上三年的时间应该可以历经起...