// 申論題
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;
}
}
這邊我們在父層的變數中也不必固定一定要 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,透過不同的分類來管理不同的辦法。
好的~今天的文章就先到這裡嚕,希望對各位有幫助!汪汪~