iT邦幫忙

0

Javascript 進階 5-5 閉包進階:工廠模式及私有方法

首先我們先來看看下面的例子

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

var fn = arrFunction();
fn[0]();
fn[1]();
fn[2]();

請問各位,覺得會分別印出多少呢結果呢?

https://ithelp.ithome.com.tw/upload/images/20200113/201217700dqb8DoxRX.png

可以看到都是印出 i = 3 的狀況

那麼我們先來檢查一下 fn 裡面是甚麼

https://ithelp.ithome.com.tw/upload/images/20200113/20121770D14H00JBJN.png

如同預期, fn 裡面是我們 push 進去的三段函式,而裡面參照的 i 很明顯是在 () 父層宣告的變數。

那麼為什麼會都取得3呢? 在這個地方要思考一下, 我們在執行這個閉包的時候,父層的全域變數並非一成不便喔,我們可以透過不同的方式去控制他,這個地方我們可以換一個方式檢視。

// 申論題
function  arrFunction () {
    var arr = [];
    for (var i = 0; i < 3; i++) {
        arr.push(function () {
            console.log(i);
        });
    }
    
    console.log('i', i); // 加這行
    return arr;
}

var fn = arrFunction();
fn[0]();
fn[1]();
fn[2]();

https://ithelp.ithome.com.tw/upload/images/20200113/20121770V812N0JtRB.png

也就是說,在執行完這個 for 迴圈的時候呢,i就已經是3了,而我們事後再進行呼叫的話,當然就都是印出3瞜!

那如果我們想要的是依序印出 0 1 2 的話該怎麼做?

可以利用到我們之前介紹到的立即函式 IIFE 進行修改,其中的一個功能就是限制作用域

// 申論題
function  arrFunction () {
    var arr = [];
    for (var i = 0; i < 3; i++) {
        (function (j) { // 改成 j
            arr.push(function () { 
                console.log(j); // 改成印出 j
            });
        })(i); // 每次累加的 i 都傳入立即函式中
    }
    return arr;
}

var fn = arrFunction();
fn[0]();
fn[1]();
fn[2]();

透過這樣的方式就可以印出 0 1 2 結果瞜!

那麼另外還有一種方式,是通過 ES6 let 的宣告函示的方法, 也可以印出 0 1 2 這樣結果的方式

// 申論題
function  arrFunction () {
    var arr = [];
    for (let i = 0; i < 3; i++) {
        arr.push(function () {
            console.log(i);
        });
    }
    return arr;
}

var fn = arrFunction();
fn[0]();
fn[1]();
fn[2]();

好的,接下來看上一篇文章介紹到的例子~

function storeMoney() {
    var money = 1000;
    return function (price) {
        money = money + price;
        return money;
    }
}

這邊我們在父層的變數中也不必固定一定要 1000,可以優化成預設變數的樣子

// 函式工廠
function storeMoney (initValue) {
    var money = initValue || 1000;
    return function (price) {
        money = money + price;
        return money;
    }
}

var MingMoney = storeMoney(100);
console.log(MingMoney(500));

這樣的感覺又稱為 函式工廠,透過這個函式工廠,你可以給他不同的值,但是呢又會做相同的事情。

除此之外,閉包還有另外一種形式叫做 私有方法

我們沿用上方的例子,我們執行這個 storeMoney 裡面回傳的子函式,但它都只會做一樣的事情,就是把傳入的數值累加,但是實際狀況並不是只有加錢啊,小明應該也會想花錢吧!也會想知道現在有多少錢吧!

那我們該怎麼滿足這樣的需求呢? 就是利用 私有方法 定義不同的方法!

// 函式工廠
function storeMoney (initValue) {
    var money = initValue || 1000;
    // 私有方法
    return {
        increase: function (price) {
            money += price;
        },
        decrease: function (price) {
            money -= price;
        },
        value: function (price) {
            return money;
        }
    }
}

我們在原本要回傳函式的地方回傳了一個物件,物件中包含了許多可能會用到的私有方法

這樣很明顯,如果我們需要調用的時候呢,就可以

var MingMoney = storeMoney(100);

MingMoney.increase(100);
MingMoney.increase(100);
MingMoney.increase(300);
MingMoney.increase(290);

MingMoney.decrease(310);
console.log(MingMoney.value());

透過這樣的方式呢,我們就可以讓一個閉包的功能得到不同面向的實用性。

也可以針對不同的需求寫出不同的 閉包 function,透過不同的分類來管理不同的辦法。

好的~今天的文章就先到這裡嚕,希望對各位有幫助!汪汪~


1 則留言

0
sx0800
iT邦新手 5 級 ‧ 2020-01-15 08:42:02

第一個申論題是主管太貓離職意志達80%後才會出現的碼。

哈哈哈~XD

沒有拉~就之前有被問到過的

我要留言

立即登入留言