为了转生而点技能-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):

http://img2.58codes.com/2024/20143762R1sov5iVzp.jpg


console.log('i', i):

因为闭包特性,会把 for 迴圈中的i带入迴圈中的内部函式,而i会等迴圈结束后才会把最后i的值带入函式,无法累次带进,原因就是 "var i 的作用域 (scope) 最小单位是 function,不是 for "。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));

参考文章:

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【ES6】let 与 const 用法这些就够了:https://www.itread01.com/xpyqp.html从ES6开始的JavaScript学习生活-Closure 闭包:https://eyesofkids.gitbooks.io/javascript-start-from-es6/content/part4/closure.html

关于作者: 网站小编

码农网专注IT技术教程资源分享平台,学习资源下载网站,58码农网包含计算机技术、网站程序源码下载、编程技术论坛、互联网资源下载等产品服务,提供原创、优质、完整内容的专业码农交流分享平台。

热门文章