Featured image of post 【JavaScript 变数】变数类型介绍:Closure 闭包

【JavaScript 变数】变数类型介绍:Closure 闭包

【JavaScript 变数】变数类型介绍:Closure 闭包

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

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
All rights reserved,未經允許不得隨意轉載
Built with Hugo
主题 StackJimmy 设计