首先我们先来看看下面的例子
// 申论题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,透过不同的分类来管理不同的办法。
好的~今天的文章就先到这里噜,希望对各位有帮助!汪汪~