Photo by Mohammad Rahmani on Unsplash
什麽是 Closure ?
- 当你有个
想保护起来
的状态,但又会不停地修改该状态,就可以使用闭包回传指定的修改方法,所以闭包接收的就是一个 function 内容。 - 一般 function 执行完之后,里面的资源就会全部被释放掉( 垃圾回收机制 ),而 Closure 可以保存着里面的状态
若资源不释放可能会造成 memory leak 问题,要注意
Closure 的好处
- 可以保存状态
- 不需要用到容易汙染的全域变数,也可以让外部修改到状态。
闭包是个 捕捉了外部函式变数
(或使之继续存活)的函式
const foo = () => {
let name = 'hi';
// closure 闭包函式
const bar = () => {
// 使用外层变数
// KJ
console.log(name);
}
bar();
}
foo();
基本上函式离开执行环境时,也会同时将佔用的记忆体空间给释放出来
。
例如以上 name 变数
应该在执行完毕就会在 memory (记忆体) 中被清掉。
但因为 closure 特性此 name 变数
还会继续被保留
运用 closure 特性让变数可以一直被保留并且做运算
var storyWriter = function(){
var story = "";
var addWords = function(string){
story = story + string
return story.trim();
}
var erase = function(){
story = "";
}
return {
addWords: addWords,
erase: erase
}
}
let writer = storyWriter();
writer.addWords('444');
writer.addWords('555');
let words = writer.addWords('666');
// 444555666
console.log(words);
取用变数范围
const globalVariable = `global variable`;
const outerFunc = (outerParam) => {
const outerVariable = `outer variable`;
let innerFunc = (innerParam) => {
const innerVariable = `inner variable`;
// 可取用全域变数
console.log(`[inner] globalVariable: ${globalVariable}`)
// 可取用外层变数
console.log(`[inner] outerVariable: ${outerVariable}`)
// 可取用本身变数
console.log(`[inner] innerVariable: ${innerVariable}`)
// 可取用外层参数
console.log(`[inner] outerParam: ${outerParam}`);
// 可取用本身参数
console.log(`[inner] innerParam: ${innerParam}`);
}
// 呼叫内部函式
innerFunc(`inner param`);
// 可取用全域变数
console.log(`<outer> globalVariable: ${globalVariable}`)
// 可取用本身变数
console.log(`<outer> outerVariable: ${outerVariable}`)
// 可取用本身参数
console.log(`<outer> outerParam: ${outerParam}`);
}
outerFunc(`outer param`);
// [inner] globalVariable: global variable
// [inner] outerVariable: outer variable
// [inner] innerVariable: inner variable
// [inner] outerParam: outer param
// [inner] innerParam: inner param
// <outer> globalVariable: global variable
// <outer> outerVariable: outer variable
// <outer> outerParam: outer param
闭包内的 this 变数
var myCar = {
color: `Blue`,
logColor: function() {
var self = this;
// In logColor — this.color: Blue
console.log(`In logColor — this.color: ` + this.color);
// In logColor — self.color: Blue
console.log(`In logColor — self.color: ` + self.color);
(function() {
// In IIFE — this.color: undefined
console.log(`In IIFE — this.color: ` + this.color);
// In IIFE — self.color: Blue
console.log(`In IIFE — self.color: ` + self.color)}
)()
},
}
myCar.logColor();
函数用新写法会变成不是
undefined
????
var myCar = {
color: `Blue`,
logColor: function() {
var self = this;
// In logColor — this.color: Blue
console.log(`In logColor — this.color: ` + this.color);
// In logColor — self.color: Blue
console.log(`In logColor — self.color: ` + self.color);
(() => {
// In IIFE — this.color: Blue
console.log(`In IIFE — this.color: ` + this.color);
// In IIFE — self.color: Blue
console.log(`In IIFE — self.color: ` + self.color)}
)()
},
}
myCar.logColor();
Closure 应用
快取,拿来避免重複的运算
// 假设 complex 要花费很多时间
function complex(num) {
console.log('caculating');
return num * num * num;
}
function Cache(func) {
let ans = {};
return function (num) {
if (ans[num]) {
// ans 有存过,直接回传
return ans[num];
}
// 没存过,丢入 ans 并回传
return ans[num] = func(num);
}
}
const CachedComplex = Cache(complex);
// 'caculating',1000 => 跑运算结果
console.log(CachedComplex(10));
// 1000 => 直接拿值
console.log(CachedComplex(10));
// 1000 => 直接拿值
console.log(CachedComplex(10));
Reference
- [面试] 前端工程师一定要会的 JS 观念题-中英对照之上篇. 提供一个面试目录的概念,并不会详细解释每一题,但会提供当初我在面试前准备的中英文… | by Hannah Lin | Starbugs Weekly 星巴哥技术专栏 | Medium
- Variable scope, closure
- 重新认识 JavaScript: Day 19 闭包 Closure - iT 邦帮忙::一起帮忙解决难题,拯救 IT 人的一天
- [第十七週] JavaScript 进阶:什麽是闭包 Closure 与实际应用 | Yakim shu
Donate KJ 贊助作者喝咖啡
如果這篇文章對你有幫助的話,可以透過下面支付方式贊助作者喝咖啡,如果有什麼建議或想說的話可以贊助並留言給我
If this article has been helpful to you, you can support the author by treating them to a coffee through the payment options below. If you have any suggestions or comments, feel free to sponsor and leave a message for me!
方式 Method | 贊助 Donate |
PayPal | https://paypal.me/kejyun |
綠界 ECPay | https://p.ecpay.com.tw/AC218F1 |
歐付寶 OPay | https://payment.opay.tw/Broadcaster/Donate/BD2BD896029F2155041C8C8FAED3A6F8 |