函數及作用域

函數及作用域

函數作用域

函數有個隱藏的屬性[[scope]],這個屬性就是作用域,其存儲了運行期上下文的集合。

[[scope]]存儲運行期上下文集合,這些集合呈鏈式關係,就是作用域鏈。

[[scope]]屬性結構

第一個元素 >>> 當前運行函數的 ActivationObject

第二個元素 >>> 當前運行函數父函數的 ActivationObject

第三個元素 >>> 當前運行函數父函數的父函數的 ActivationObject

…………

最後元素 >>> GlobalObject

<script type = "text/javascript">
	function a(){
		function b(){
			function c(){
				function d(){
				}
				d();
			}
			c();
		}
		b();
	}
	function e(){
	}
	// a 和 e 函數定義時它們的 [[scope]] 屬性中只有一個元素,就是 GlobalObject(全局運行時上下文)
	//當要執行 a 函數時,a 函數就創建自己的 ActivatonObject(運行時上下文),存儲在屬性[[scope]]中,並放置到頂端(第1個元素)
	//這時 a 函數的[[scope]]屬性的內容是
	//第一個元素   ActivationObject(a的運行時上下文)
	//第二個元素   GlobalObject(全局的運行時上下文)
	a();
	//當執行 a 函數時,b 函數運行前,b函數屬性[[scope]]引用了函數 a 的[[scope]]屬性,並且b函數創建自己的 ActivationObject。
	//這時 b 函數的[[scope]]屬性的內容是
	//第一個元素   ActivationObject(b的運行時上下文)
	//第二個元素   ActivationObject(a的運行時上下文)
	//第三個元素   GlobalObject(全局的運行時上下文)
	//當 b 函數執行時,查找變量的順序是[[scope]]屬性,從上往下查找。直到找到第一個符合的停止。
	//當 b 函數執行完後,銷燬自己創建ActivationObject
	//這時 b 函數的[[scope]]屬性的內容變爲
	//第一個元素   ActivationObject(a的運行時上下文)
	//第二個元素   GlobalObject(全局的運行時上下文)
	//當執行 b 函數時,c 函數運行前,c函數屬性[[scope]]引用函數 b 的[[scope]]屬性,並且c函數創建自己的 ActivationObject。
	//以此類推,直到所有函數執行完畢。
</script>

閉包:

內部函數被返回到外部時,內部函數本身存着父函數的ActivationObject,即使父函數執行完,取消了對 ActivationObject引用,但內部函數依然可以存取父函數變量。這樣就產生閉包。閉包會導致原有作用域鏈不釋放,造成內存泄漏。

閉包的作用:實現公有變量(累加器)、緩存(存儲結構)、實現封裝,屬性私有化、模塊化開發,防止污染全局變量。

<script type = "text/javascript">
	function a(){
		var num = 0;
		function b(){
			num ++;
			document.write("num = ",num,"<br/>")
		}
		return b;
	}
	var demo = a();
	demo();//1
	demo();//2
	demo();//3
</script>

閉包應用:緩存

<script type = "text/javascript">
	function eater(){
		var food = [];
		var obj = {
			eat:function(){
				if(food.length < 1){
					document.write("There is no food!<br/>");
				}
				else{
					document.write("i am eating " + food[food.length - 1],"<br/>");
					food.pop();
				}
			},
			push:function(myFood){
				food.push(myFood);
			}
		}
		return obj;
	}
	var eater1 = eater();
	eater1.push("apple");
	eater1.push("banana");
	eater1.eat();
	eater1.push("orange");
	eater1.eat();
	eater1.push("cake");
	eater1.eat();
	eater1.eat();
	eater1.push("banana");
	eater1.eat();
	eater1.eat();
</script>

立即執行函數(初始化功能的函數)

應用在只執行一次的函數。只有函數表達式才能被執行符號()執行,函數聲明不能被執行。

<script type = "text/javascript">
	(function(){document.write("ohohoh!!","<br/>")}());//W3C推薦立即執行函數格式
	(function(){document.write("ohohoh!!","<br/>")})();
	var x =(function(a,b,c){
          return a + b + c;
			}(1,2,3))
	document.write(x,"<br/>");
	var y = function demo(){
		document.write("hahaha!!!","<br/>")
	}();
	//function error(){document.write("ohohoh!!","<br/>");}();函數聲明不能被執行
	+function error(){document.write("ohohoh!!","<br/>");}(); 
</script>

立即執行函數與閉包應用

<script type = "text/javascript">
	//立即執行函數,閉包保存循環變量 ii 的使用方式。
	function test(){
		var arr = [];
		for (var i = 0; i < 10; i++) {
			(function(ii){
				arr[ii] = function(){
				document.write("i = " + i + " ii = " + ii + "<br/>")
			}	
			}(i))
		}
		return arr;
	}
	var myArr = test();
	for(var j = 0;j < myArr.length;j++){
		myArr[j]();
	}
</script>
" ii = " + ii + "<br/>")
			}	
			}(i))
		}
		return arr;
	}
	var myArr = test();
	for(var j = 0;j < myArr.length;j++){
		myArr[j]();
	}
</script>
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章