1. 程式人生 > 其它 >理解js閉包9大使用場景,大廠面試官好自為之!

理解js閉包9大使用場景,大廠面試官好自為之!

技術標籤:javascriptjavascript

目錄

閉包可以說無處不在,所以閉包的幾個常用場景,很值得研究一番,如果對閉包還有疑問,可以翻看我之前閉包 的文章。

1.返回值(最常用)

2.函式賦值

3.函式引數

5.迴圈賦值

6.getter和setter

7.迭代器(執行一次函式往下取一個值)

8.首次區分(相同的引數,函式不會重複執行)

9.快取

理解了閉包的使用場景,好自為之的就是面試官了,哈哈!


閉包可以說無處不在,所以閉包的幾個常用場景,很值得研究一番,如果對閉包還有疑問,可以翻看我之前閉包 的文章。

1.返回值(最常用)

	//1.返回值 最常用的
		function fn(){
			var name="hello";
			return function(){
				return name;
			}
		}
		var fnc = fn();
		console.log(fnc())//hello

這個很好理解就是以閉包的形式將 name 返回。

2.函式賦值

        var fn2;
		function fn(){
			var name="hello";
			//將函式賦值給fn2
			fn2 = function(){
				return name;
			}
		}
		fn()//要先執行進行賦值,
		console.log(fn2())//執行輸出fn2

在閉包裡面給fn2函式設定值,閉包的形式把name屬性記憶下來,執行會輸出 hello。

3.函式引數

		function fn(){
			var name="hello";
			return function callback(){
				return name;
			}
		}
		var fn1 = fn()//執行函式將返回值(callback函式)賦值給fn1,
		
		function fn2(f){
			//將函式作為引數傳入
			console.log(f());//執行函式,並輸出
		}
		fn2(fn1)//執行輸出fn2

用閉包返回一個函式,把此函式作為另一個函式的引數,在另一個函式裡面執行這個函式,最終輸出 hello

4.IIFE(自執行函式)

	(function(){
			var name="hello";
			var fn1= function(){
				return name;
			}
			//直接在自執行函式裡面呼叫fn2,將fn1作為引數傳入
			fn2(fn1);
		})()
		function fn2(f){
			//將函式作為引數傳入
			console.log(f());//執行函式,並輸出
		}

直接在自執行函式裡面將封裝的函式fn1傳給fn2,作為引數呼叫同樣可以獲得結果 hello

5.迴圈賦值

	//每秒執行1次,分別輸出1-10
	for(var i=1;i<=10;i++){
		(function(j){
			//j來接收
			setTimeout(function(){
				console.log(j);
			},j*1000);
		})(i)//i作為實參傳入
	}

如果不採用閉包的話,會有不一樣的情況,可以看我自己閉包 的文章。

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是兩個函式
	console.log(fn1.getName());//getter
		fn1.setName('world');//setter修改閉包裡面的name
	console.log(fn1.getName());//getter

第一次輸出 hello 用setter以後再輸出 world ,這樣做可以封裝成公共方法,防止不想暴露的屬性和函式暴露在外部。

7.迭代器(執行一次函式往下取一個值)

		var arr =['aa','bb','cc'];
		function incre(arr){
			var i=0;
			return function(){
				//這個函式每次被執行都返回陣列arr中 i下標對應的元素
				 return arr[i++] || '陣列值已經遍歷完';
			}
		}
		var next = incre(arr);
		console.log(next());//aa
		console.log(next());//bb
		console.log(next());//cc
		console.log(next());//陣列值已經遍歷完

8.首次區分(相同的引數,函式不會重複執行)

 var fn = (function(){
				var arr=[];//用來快取的陣列
					return function(val){
						if(arr.indexOf(val)==-1){//快取中沒有則表示需要執行
							arr.push(val);//將引數push到快取陣列中
							console.log('函式被執行了',arr);
							//這裡寫想要執行的函式
						}else{
							console.log('此次函式不需要執行');
						}
						console.log('函式呼叫完列印一下,方便檢視已快取的陣列:',arr);
					}
				})();
		
		fn(10);
		fn(10);
		fn(1000);
		fn(200);
		fn(1000);

執行結果如下:

可以明顯的看到首次執行的會被存起來,再次執行直接取。

9.快取

//比如求和操作,如果沒有快取,每次呼叫都要重複計算,採用快取已經執行過的去查詢,查詢到了就直接返回,不需要重新計算
	 
	 var fn=(function(){
	 	var cache={};//快取物件
	 	var calc=function(arr){//計算函式
	 		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轉換成陣列
	 		var key=args.join(",");//將args用逗號連線成字串
		 	var result , tSum = cache[key];
		 	if(tSum){//如果快取有	
		 		console.log('從快取中取:',cache)//列印方便檢視
		 		result = tSum;
		 	}else{
		 		//重新計算,並存入快取同時賦值給result
			 	result = 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);

輸出結果:

理解了閉包的使用場景,好自為之的就是面試官了,哈哈!