前言
了解什麼是工廠模式及私有方法,針對不同的需求寫出不同的閉包 function
我們先來看看下面的例子,請問各位覺得會分別印出多少呢結果呢?
// 申論題
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]();
可以看到都是印出 i = 3 的狀況
那麼我們先來檢查一下 fn 裡面是什麼
如同預期, 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]();
也就是說,在執行完這個 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;
}
}
我們在父層的變數中 var money = 1000; 也不必固定一定要 1000,可以優化成預設變數的樣子
// 函式工廠
function storeMoney (initValue) {
var money = initValue || 1000;
return function (price) {
money = money + price;
return money;
}
}
var MingMoney = storeMoney(100);
console.log(MingMoney(500)); // 600
像上方範例,將變數改為預設 initValue ,這樣又稱為函式工廠,透過這個函式工廠,你可以給他不同的值,但是又會做相同
的事情。
私有方法
閉包還有另外一種形式叫做私有方法
我們沿用上方的例子,我們執行這個 storeMoney 裡面回傳的子函式,但它都只會做一樣的事情,就是把傳入的數值累加,
但是實際狀況並不是只有加錢啊,小明應該也會想花錢吧!也會想知道現在有多少錢吧!
那我們該怎麼滿足這樣的需求呢 ? 就是利用私有方法定義不同的方法 !
// 函式工廠
function storeMoney (initValue) {
var money = initValue || 1000;
// 私有方法
return {
increase: function (price) {
money += price;
},
decrease: function (price) {
money -= price;
},
value: function (price) {
return money;
}
}
}
我們在原本要回傳函式的地方 return 回傳了一個物件 { } ,物件中包含了許多可能會用到的私有方法,
以上方為例就是 increase 、 decrease 、 value ,這樣很明顯,如果我們需要調用的時候呢,就可以
var MingMoney = storeMoney(100);
MingMoney.increase(100);
MingMoney.increase(100);
MingMoney.increase(300);
MingMoney.increase(290);
MingMoney.decrease(310);
console.log(MingMoney.value());
透過這樣的方式,我們就可以讓一個閉包的功能得到不同面向的實用性。
也可以針對不同的需求寫出不同的閉包 function,透過不同的分類來管理不同的辦法。