1. 程式人生 > >javascript函式閉包

javascript函式閉包

1. 事件閉包的理解

閉包是指有許可權訪問另一個函式作用域中的變數的函式。 在 javascript 語言中,閉包就是函式和該函式作用域的組合。從這 個概念上來講,在 js 中,所有函式都是閉包(函式都是物件並且函 數都有和他們相關聯的作用域鏈 scope chain)。

 官方”的解釋是:閉包是一個擁有許多變數和綁定了這些變數的 環境的表示式(通常是一個函式),因而這些變數也是該表示式的一 部分。其實這 句話通俗的來說就是:JavaScript 中所有的 function 都是一個閉包。 不過一般來說,巢狀的 function 所產生的閉包更為強大,也是大部 分時候我們所謂的“閉包”。

2. 變數的作用域 要理解閉包,首先必須理解 Javascript 特殊的變數作用域。 變數的作用域無非就是兩種:全域性變數和區域性變數。 Javascript 語言的特殊之處,就在於函式內部可以直接讀取全域性 變數。

案例:


<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8">
		<title></title>
		<script type="text/javascript">
			
//			閉包: 在js中任何一個函式都是一個閉包,但是巢狀的函式閉包作用會更大;
//			閉包: 一個函式中的變數 可以被其他函式所訪問			
			//問題: 如何從外部讀取函式內部的變數?
			//解決: 在 函式體內巢狀函式
//			function snake(){ 	  //建立一個蛇物件			
//				var color='white';  //建立屬性
//				//var length=30;
//				var width=20;
//				var height=20;
//				function snake1(){
////					var color_01='red';
//					alert(color);
//				}
//				snake1();
//			}
//			snake();  //輸出color的結果為: white
			//以上函式巢狀  是 JS中特殊的作用域立鏈  scope  chain
			//父物件的所有變數,對子物件都是可見的,反之則不成立
			
			function snake(){ 	  //建立一個蛇物件			
				var color='white';  //建立屬性
				var width=20;
				var height=20;
				function snake1(){
					return color;
				}
//				var color_01=snake1();  return color_01;
				return snake1();
			}
			alert(snake());
		</script>
	</head>
	<body>
	</body>
</html>

練習案例1:


<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8">
		<title></title>
		<script type="text/javascript">
			
//			建立一個學生 物件,具備屬性     color, height,weight
			function Student(){
				var color='yellow';
				var height=1.82;
				var weight=60; //表示體重的屬性
				
				//第一種方法 不常用(不強大);
				//return '膚色:'+color+'身高:'+height+'體重:'+weight;
				//第二種方式: 通過在函式體內定義函式 返回,功能更加強大
				function Student_01(){
					return '膚色:'+color+'身高:'+height+'體中:'+weight;
				}
				return Student_01();
			}
//			對於以上案例: Student_01() 就是一個閉包函式

			/*閉包可以使用在許多地方.它的最大作用有兩處:
				一個是前面提到的可以讀取函式內部的變數,
				另一個就是讓這些變數的值始終保持在記憶體中*/
			
		</script>
	</head>
	<body>
	</body>
</html>

案例2:

function outerFun(){
    var a=0;
  function innerFun(){
    a++;
   alert(a);
  }
}
innerFun()
上面的程式碼是錯誤的.innerFun()的作用域在 outerFun()內部,所在 outerFun()外部呼叫它是錯誤的. 改成如下,也就是閉包:
function outerFun(){
  var a=0;
  function innerFun(){
  a++;
  alert(a);
   }
  return innerFun; //注意這裡
}
var obj=outerFun();

obj(); //結果為 1
obj(); //結果為 2
var obj2=outerFun();
obj2(); //結果為 1
obj2(); //結果為 2

案例3:

<!DOCTYPE html>
<html>

	<head>
		<meta charset="UTF-8">
		<title></title>
		<script type="text/javascript">
			function outerFun() {
				var a = 0;
				alert(a);
			}
			var a = 4;
			outerFun();
			alert(a);
			//結果是 0, 4.因為在函式內部使用了
			//var 關鍵字 維護 a 的作用域在 outFun() 內部.
				function outerFun() {
					//沒有 var
					a = 0;
					alert(a);
				}
			var a = 4;
			outerFun();
			alert(a);
			//結果為 0, 0 
				//作用域鏈是描述一種路徑的術語, 沿著該路徑可以確定變數的值.當執行 a = 0 時,
				//因為沒有使用var關鍵字, 因此賦值操作會沿著作用域鏈到var a = 4;並改變其值.
		</script>
	</head>

	<body>
	</body>

</html>

案例4:

這段程式碼有兩個特點: 1、函式 b 巢狀在函式 a 內部; 2、函式 a 返回函式 b。

這樣在執行完 var c=a()後,變數 c 實際上是指向了函式 b,再執 行 c()後就會彈出一個視窗顯示 i 的值(第一次為 1)。這段程式碼其實 就建立了一個閉包,為什麼?因為函式 a 外的變數 c 引用了函式 a 內 的函式 b,

就是說: 當函式 a 的內部函式 b 被函式 a 外的一個變數引用的時候,就建立 了一個閉包。