理解JavaScript閉包9大使用場景
來源 | http://www.fly63.com/article/detial/9974?type=2
1、返回值(最常用)
//1.返回值 最常用的function fn(){var name="hello";return function(){return name;}}var fnc = fn();console.log(fnc())//hello
這個很好理解就是以閉包的形式將 name 返回。
2、函數(shù)賦值
var fn2;function fn(){var name="hello";//將函數(shù)賦值給fn2fn2 = function(){return name;}}fn()//要先執(zhí)行進(jìn)行賦值,console.log(fn2())//執(zhí)行輸出fn2
在閉包里面給fn2函數(shù)設(shè)置值,閉包的形式把name屬性記憶下來,執(zhí)行會輸出 hello。
3、函數(shù)參數(shù)
function fn(){var name="hello";return function callback(){return name;}}var fn1 = fn()//執(zhí)行函數(shù)將返回值(callback函數(shù))賦值給fn1,function fn2(f){//將函數(shù)作為參數(shù)傳入console.log(f());//執(zhí)行函數(shù),并輸出}fn2(fn1)//執(zhí)行輸出fn2
用閉包返回一個函數(shù),把此函數(shù)作為另一個函數(shù)的參數(shù),在另一個函數(shù)里面執(zhí)行這個函數(shù),最終輸出 hello
4、IIFE(自執(zhí)行函數(shù))
(function(){var name="hello";var fn1= function(){return name;}//直接在自執(zhí)行函數(shù)里面調(diào)用fn2,將fn1作為參數(shù)傳入fn2(fn1);})()function fn2(f){//將函數(shù)作為參數(shù)傳入console.log(f());//執(zhí)行函數(shù),并輸出}
直接在自執(zhí)行函數(shù)里面將封裝的函數(shù)fn1傳給fn2,作為參數(shù)調(diào)用同樣可以獲得結(jié)果 hello。
5、循環(huán)賦值
//每秒執(zhí)行1次,分別輸出1-10for(var i=1;i<=10;i++){(function(j){//j來接收setTimeout(function(){console.log(j);},j*1000);})(i)//i作為實(shí)參傳入}
如果不采用閉包的話,會有不一樣的情況。
6、getter和setter
function fn(){var name='hello'setName=function(n){name = n;}getName=function(){return name;}//將setName,getName作為對象的屬性返回return {setName:setName,getName:getName}}var fn1 = fn();//返回對象,屬性setName和getName是兩個函數(shù)console.log(fn1.getName());//getterfn1.setName('world');//setter修改閉包里面的nameconsole.log(fn1.getName());//getter
第一次輸出 hello 用setter以后再輸出 world ,這樣做可以封裝成公共方法,防止不想暴露的屬性和函數(shù)暴露在外部。
7、迭代器(執(zhí)行一次函數(shù)往下取一個值)
var arr =['aa','bb','cc'];function incre(arr){var i=0;return function(){//這個函數(shù)每次被執(zhí)行都返回?cái)?shù)組arr中 i下標(biāo)對應(yīng)的元素return arr[i++] || '數(shù)組值已經(jīng)遍歷完';}}var next = incre(arr);console.log(next());//aaconsole.log(next());//bbconsole.log(next());//ccconsole.log(next());//數(shù)組值已經(jīng)遍歷完
8、首次區(qū)分(相同的參數(shù),函數(shù)不會重復(fù)執(zhí)行)
var fn = (function(){var arr=[];//用來緩存的數(shù)組return function(val){if(arr.indexOf(val)==-1){//緩存中沒有則表示需要執(zhí)行arr.push(val);//將參數(shù)push到緩存數(shù)組中console.log('函數(shù)被執(zhí)行了',arr);//這里寫想要執(zhí)行的函數(shù)}else{console.log('此次函數(shù)不需要執(zhí)行');}console.log('函數(shù)調(diào)用完打印一下,方便查看已緩存的數(shù)組:',arr);}})();fn(10);fn(10);fn(1000);fn(200);fn(1000);
執(zhí)行結(jié)果如下:

可以明顯的看到首次執(zhí)行的會被存起來,再次執(zhí)行直接取。
9、緩存
//比如求和操作,如果沒有緩存,每次調(diào)用都要重復(fù)計(jì)算,采用緩存已經(jīng)執(zhí)行過的去查找,查找到了就直接返回,不需要重新計(jì)算var fn=(function(){var cache={};//緩存對象var calc=function(arr){//計(jì)算函數(shù)var sum=0;//求和for(var i=0;i<arr.length;i++){sum+=arr[i];}return sum;}return function(){var args = Array.prototype.slice.call(arguments,0);//arguments轉(zhuǎn)換成數(shù)組var key=args.join(",");//將args用逗號連接成字符串var result , tSum = cache[key];if(tSum){//如果緩存有console.log('從緩存中取:',cache)//打印方便查看result = tSum;}else{//重新計(jì)算,并存入緩存同時賦值給resultresult = cache[key]=calc(args);console.log('存入緩存:',cache)//打印方便查看}return result;}})();fn(1,2,3,4,5);fn(1,2,3,4,5);fn(1,2,3,4,5,6);fn(1,2,3,4,5,8);fn(1,2,3,4,5,6);
輸出結(jié)果:

評論
圖片
表情
