为了转生而点技能-JavaScript,day12(闭包Closure及回圈的闭包陷阱

闭包Closure

特徵:一个函式内的子函式,运作时会调用上层函式(或是父函式)的变数,避免父函式的变数因为没有被参照而从记忆体中释放。

        function init() {
            var name = "Mozilla";      // name 是个由 init 建立的区域变数
            function displayName() {   // displayName() 是内部函式(子函式),一个闭包
                alert(name);           // 使用了父函式宣告的变数:name
            }
            displayName();
        }
        init();

闭包通常都会用回传 (return) 的方式,取得外部函式的变数 or 参数作运用。

例子1:

        function storeMoney() {
            var money = 1000;
            return function (price) {
                money = money + price;
                return money;
            }
        };
        console.log(storeMoney()); 
        //return 即为表达式,代表function storeMoney会从return回传一个值出来,因为无参数,所以传出function (price)。
        
        console.log(storeMoney()(100)); 1100

        var Kingmoney = storeMoney();
        console.log(Kingmoney);          //结果同console.log(storeMoney())
        console.log(Kingmoney(1000));    //2000
        console.log(Kingmoney(1000));    //3000 因为变数money一直被子函式参考,所以不会从记忆体中消除。

        var Queenmoney = storeMoney();
        console.log(Queenmoney(20));    //1020,参数更改
        console.log(Queenmoney(20));    //1040 

例子2(回圈的闭包陷阱):

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

console.log(arr):

https://ithelp.ithome.com.tw/upload/images/20211201/20143762R1sov5iVzp.jpg


console.log('i', i):

  1. 因为闭包特性,会把 for 回圈中的i带入回圈中的内部函式,而i会等回圈结束後才会把最後i的值带入函式,无法累次带进,原因就是 "var i 的作用域 (scope) 最小单位是 function,不是 for "。
  2. i 的作用域在 arrFunction( ),在 i 进入arr.push(function () {console.log(i);}之前就会先把回圈跑完,再将最後的值带入,所以会出现console.log('i', i)为 i 3的结果。

var arr = []:

因为变数i皆会等回圈结束後才会把最後i的值带入函式,所以无论参数是多少,子函数都会参考到 for 回圈中的i。


解回圈的闭包陷阱:

方法一:立即函式

利用立即函式的特性,每执行一次回圈,立即执行一次立即函式;本例利用回圈的变数c填入立即函数的参数(newc)位置。

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

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

方法二:利用let宣告取代回圈里的var宣告

        function arrFunction() {
            var arr = [];
            for (let c = 0; c < 3; c++) {

                arr.push(function () {
                    console.log(c);
                });

            }
            console.log(arr);
            // console.log('c', c);

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

补充:参数预设值的写法

        function carprice(GPS) {
            var car = 1000;
            var sum = 0;
            GPS = GPS || 0;          //当GPS有被填入参数值的时候选择参数值,如果没填入则为0。
            return function (GPS) {
                sum = GPS + car;
                return sum;
            };
        };
        var Tom = carprice();
        console.log(Tom(1000));

参考文章:

  1. JS-闭包 (Closure) 观念整理:https://medium.com/chloelo925/js-%E9%96%89%E5%8C%85-closure-%E8%A7%80%E5%BF%B5%E6%95%B4%E7%90%86-346c32be3e30
  2. 【ES6】let 与 const 用法这些就够了:https://www.itread01.com/xpyqp.html
  3. 从ES6开始的JavaScript学习生活-Closure 闭包:https://eyesofkids.gitbooks.io/javascript-start-from-es6/content/part4/closure.html

<<:  实施零信任架构以防止横向移动,XACML最不可能进行身份验证

>>:  用visual studio写动物图监网页

[day2] 付款流程 & 取得(Nonce)

资料准备 啊以为第二天开始就是程序码喔,NONONO,要接入金融机构的系统,不是任何人都能直接跑进去...

Day21:今天来聊一下Azure Sentinel 介绍

传统的安全性资讯与事件管理(SIEM)系统通常需要很长的时间 来安装及设定。这类系统在设计时也不一定...

20.unity换场景

今天要盖出阿嬷家!让小红帽走进阿嬷家,找到阿嬷。 1.新建场景 右键 > Create >...

Fortran 语言和你 SAY HELLO!!

第二十四天 各位点进来的朋友,你们好阿 小的不才只能做这个系列的文章,但还是希望分享给点进来的朋友,...

第7车厢-讨厌~叫人家开要干嘛?触发check事件应用篇

本篇延续第六篇按钮开关样板,来触发之後的行为 昨天做了一个开关,那要怎麽透过科好的按钮,来判断之後...