04 Function

Function類型:
每個函數都是Function類型的實例,而且都與其他引用類型一樣具有屬性和方法,由於函數是對象,因此函數名實際上是一個指向函數對象的指針。
函數的三種定義方式:

第一種:
	function sum(num1,num2){
		return num1+num2;
	}
第二種:
	var sum = function(num1,num2){
		return num1+num2;
	};
第三種:
	var sum = new Function("num1","num2","return num1+num2");

第二種方式function後面沒有函數名,因爲通過變量sum即可引用函數,另外函數末尾有分號,就像聲明變量一樣。
由於函數名是指向函數的指針,因此一個函數可以有多個名字
var anothersum = sum;
alert(anothersum(10,10));//20


沒有重載:因爲函數名是指針,因此可以理解javascript沒有重載,因爲在第二個同名函數被定義的時候,函數名指向了另一個函數對象。

函數聲明和函數表達式:

函數聲明:解析器會先讀取函數聲明,使其在執行任何代碼之前可用
函數表達式:必須等到解析器執行到它所在的代碼行,纔會真正被解釋執行。
Example 1:  正常運行;
alert(sum(10,10));
function sum(num1,num2){
	return num1+num2;
}

Example 2: 運行出錯,函數位於一個初始化語句塊中,而不是一個函數聲明中
alert(sum(10,10));
var sum = function(num1 , num2){
	return num1+num2;
}


作爲值的函數
因爲ECMAScript中的函數名本身就是變量,所以函數本身也可以作爲值來使用,也就是說可以像傳遞參數一樣把一個參數傳遞給另一個參數,而且可以將一個函數作爲另一個函數的結果返回。


函數的內部屬性:
arguments和this
arguments主要是用來保存參數,這個對象還有一個屬性叫callee,這是一個指針,指向擁有這個arguments對象的函數。
callee用法:在遞歸算法中消除耦合

this:函數執行時所處的作用域

function factorial(num){
	if(num<=1){
		return 1;
	}else{
		return num * factorial(num-1);
	}
}

function factorial(num){
	if(num<=1){
		return 1;
	}else{
		return num * arguments.callee(num-1);
	}
}



函數的屬性和方法
函數是對象,因此具有屬性和方法
length屬性:函數希望接受的命名參數的個數
prototype屬性:是保存引用類型的所有實例方法的真正所在,在創建自定義類型和實現繼承的時候,prototype屬性的作用是極其重要的。
每個函數都有兩個非繼承而來的方法,call()和apply(),這兩個方法用途都是在特定的域中調用函數,apply方法有兩個參數,一個是在其中運行函數的作用域,另一個是參數數組,第二個參數可以是Array也可以是arguments
而是用call方法時,第二個參數必須一一列舉出來。

Example 1:
function sum(num1,num2){
	return num1+num2;
}

function callSum1(num1,num2){
	return sum.apply(this,arguments);
}

function callSum2(num1,num2){
	return sum.apply(this,[num1,num2]);
}


Example 2:

function callSum3(num2,num1){
	return sum.call(this,num1,num2);
}

apply和sum真正的用處在於:能夠擴充函數賴以運行的作用域
window.color= "red";
var o={color:"blue"};
function sayColor(){
	alert(this.color);
}
sayColor();//red
sayColor.call(this);//red
sayColor.call(window);//red
sayColor.call(o);//blue函數的執行環境不一樣了,此時函數體內的this指向了o

函數的toString和toLocaleString方法都返回函數的代碼。


<span style="font-size:18px;"><strong> 函數雖然是一個對象,但是卻和對象有一些區別,對象是通過引用的指向完成對象的賦值的,而函數卻是通過對象的拷貝來完成的所以fn1雖然變了,並不會影響fn2</strong></span>

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN"
   "http://www.w3.org/TR/html4/strict.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" lang="en">
<head>
	<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
	<title>js01_hello</title>
	<meta name="author" content="Administrator" />
	<script type="text/javascript">
	//第一種定義方式
	function fn1() {
		alert("fn1");
	}
	//函數就是一個非常特殊的對象,是一個Function類的實例,其實在內存中存儲的操作是通過一個鍵值對來存儲的
	alert(typeof fn1);
	
	//由於函數是一個對象,所以可以通過如下方式定義
	//以下是通過函數的拷貝來完成賦值,兩個引用並沒有指向同一個對象
	var fn2 = fn1;
	fn2();
	fn1 = function() {
		alert("fnn1");
	}
	/**
	 * 函數雖然是一個對象,但是卻和對象有一些區別,對象是通過引用的指向完成對象的賦值的,而函數卻是通過對象的拷貝來完成的
	 * 所以fn1雖然變了,並不會影響fn2
	 */
	fn2();
	fn1();
	
	/**
	 * 對於對象而言,是通過引用的指向來完成賦值的,此時修改o1或者o2會將兩個值都完成修改
	 */
	var o1 = new Object();
	var o2 = o1;
	o2.name = "Leon";
	alert(o1.name);
	</script>
</head>
<body>
</body>
</html>







發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章