iT邦幫忙

2021 iThome 鐵人賽

DAY 25
0
自我挑戰組

JavaScript 核心觀念系列 第 25

【Day25】閉包進階:工廠模式及私有方法

我們先來看一段閉包程式碼

function arrFunction() {
    const arr = [];
    for (var i = 0; i < 3; i++) {
        arr.push(function(){
            console.log(i);
        });
    };
    
    console.log(arr);
    
    return arr;
}

const fn = arrFunction();

fn[0]();
fn[1]();
fn[2]();

arrFunction() 是一個閉包,

我們在 arr 陣列中 push 三個函式,

那麼為何顯示的結果都是 3 而不是 012 呢?

我們可以在 arrFunction() 中,

觀察 for 迴圈執行完後的 i 值為何

function arrFunction() {
    const arr = [];
    for (var i = 0; i < 3; i++) {
        arr.push(function(){
            console.log(i);
        });
    };
    
    console.log('i', i);
    
    return arr;
};

const fn = arrFunction();

從結果得知當我們將 arrFunction() 賦予到 fn 時,

此時的 i 值就已經是 3 了,

因為此時 arrFunction() 的作用域中 i 最後結果為 3

因此執行 arr 內的函式時,只會取得 3 這個值,

那如果要顯示 012 的話,我們有兩種方法可以使用

1. 立即函式

function arrFunction() {
    const arr = [];
    for (var i = 0; i < 3; i++) {
        (function(j){
            arr.push(function(){
            console.log(j);
            });
        })(i);        
    };
    
    console.log(arr);
    
    return arr;
}

const fn = arrFunction();

fn[0]();
fn[1]();
fn[2]();

此時可看到結果確實顯示 012

那是因為立即函式有自己的作用域,

當參數 i 代入立即函式時,

此時 arr 中的所取得的值就是作為參數帶進來的值,

因此結果才會顯示 012

2. 用 let 宣告 i

function arrFunction() {
    const arr = [];
    for (let i = 0; i < 3; i++) {
        arr.push(function(){
            console.log(j);
        });       
    };
    
    console.log(arr);
    
    return arr;
}

const fn = arrFunction();

fn[0]();
fn[1]();
fn[2]();

此時 i 的作用域在 for 迴圈的 {}

所以顯示結果為 012

工廠模式及私有方法

工廠模式

function storeMoney(initValue) {
    let money = initValue || 1000;
    return function (price) {
        money += price;
        return money;
    };
};

const mingMoney = storeMoney(300);

console.log(mingMoney(500));  // 800

const weiMoney = storeMoney(3000);

console.log(weiMoney(500));  // 3500

該範例我們透過閉包傳入不同的值,來做相同的事情,稱為工廠模式

私有方法

function storeMoney(initValue) {
    let money = initValue || 1000;
    return {
        increase: function(price){
            money += price
        },
        decrease: function(price){
            money -= price
        },
        value: function() {
            console.log(money);
        }
    };
};

const mingMoney = storeMoney(300);

mingMoney.increase(200);
mingMoney.increase(200);
mingMoney.increase(200);
mingMoney.decrease(300);

console.log(mingMoney.value());  // 600

在範例中我們在 return 中回傳物件,

之後在物件中建立許多方法,

像這種使用閉包來回傳各種方法的行為,稱為私有方法


上一篇
【Day24】閉包(Closure)
下一篇
【Day26】this - 物件的方法調用
系列文
JavaScript 核心觀念30

尚未有邦友留言

立即登入留言