????? 在javascript中,function作為一個關鍵字有兩方面的應用。
???? a、可以定義函數。
???? b、可以定義一個數據類型。這里只介紹函數。關于function定義類的功能在對象中介紹。
1、函數的概念
??? javascript中提供了許多預定義函數,我們可以直接使用,比如Math.sin();eval()等。
我們也可以定義自己的函數。有以下四種方法:

a、function add(x,y){return x+y;}
b、var add = function(x,y){return x+y;}
c、var add = new Function("x","y","return x+y;");
d、var add =function a(x,y){return x+y;}

在這,如果用add(2,3);調用,返回的結果都是5。但它們使用有很大的區別,后面在詳細解釋。

2、函數的參數
???? 回想上一篇提到函數的調用對象。雖然我們不能訪問它,看不見,但引入這個概念確實可以方便我們解釋很多東西。
???? 在一個函數體內,標識符arguments有特殊含義。它是調用對象的一個特殊屬性。

< SCRIPT?LANGUAGE = " JavaScript " >
function ?add(x,y) {
document.writeln('x
= ' + x);
document.writeln('y
= ' + y);
document.writeln('arguments[
0 ] = ' + arguments[ 0 ]);
document.writeln('arguments[
1 ] = ' + arguments[ 1 ]);
arguments[
0 ] = 11 ;
document.writeln('arguments[
0 ] = ' + arguments[ 0 ]);
return ?x + y;
}

document.writeln(add(
2 , 3 ));
</ SCRIPT >

???? 看例子,基本你可以把arguments當成個數組使用,但并不是真正的數組。
??? 雖然arguments.length and arguments[index]可以在函數內改變,但建議你不要在函數內改變它們。關于arguments的具體用法可以看prototype.js.
arguments還有個屬性 callee.引用當前正在執行的函數。

?

< SCRIPT?LANGUAGE = " JavaScript " >
function ?add(x,y) {
????document.writeln(arguments.callee);
????document.writeln(
typeof (arguments.callee));
????
return ?x + y;
}

document.writeln(add);
document.writeln(
typeof (add));
document.writeln('
</ br >-----------------------</ br > ');
add();
</ SCRIPT >

3、函數是一種數據類型
??? 在javascript中,函數不但能象java一樣當成語言的語法特性,還可以象字符串、數字、日期一樣當成一種數據。
??? var add=function(x,y){return x+y;};其實我們函數的定義都是把函數附值給變量。函數不但可以附值給變量,還可以當成參數傳遞。

?

< SCRIPT?LANGUAGE = " JavaScript " >
var ?add = function (x,y) { return ?x + y;} ;
var ?fun = add;
function ?opetate(fun,x,y) {
????
return ?fun(x,y);
}

alert(opetate(fun,
2 , 3 ));
</ SCRIPT >

?

其實javascript的熟手不會在全局變量里(直接在js文件中)定義函數,都會定義在全局變量的屬性字段中。如

?

< SCRIPT?LANGUAGE = " JavaScript " >
??
var ?MyLib = {} ;
??MyLib.fun1
= function () {} ;
??MyLib.fun2
= function () {} ;
??alert(MyLib);
??alert(MyLib.fun1);
</ SCRIPT >

如果這種寫法,我們就基本不會和別人寫的程序發生命名上的沖突了。

4、函數的生命周期
??? 在變量里我們知道函數有個預編譯過程,這個過程我們也看到不到,另外函數定義不同寫法情況也不同。所以,感覺函數的執行過程很是復雜。

?

< SCRIPT?LANGUAGE = " JavaScript " >
??fun1();
??alert(fun1);
// ///////////把以下代碼放到定義最后面可以執行。
??fun2();
??alert(fun2)
??fun3();
??alert(fun3)
??
// /////////////////////////
?? function ?fun1() {document.writeln('fun1?run ! ')}
??
var ?fun2? = function () {document.writeln('fun2?run ! ')} ;
??
var ?fun3? = new ?Function( " document.writeln('fun3?run!') " );
</ SCRIPT >


a、javascript預編譯過程(在html中, </head>前后,<body>內外有特殊情況,這指純.js文件中)
??? javascript的預編譯我認為是個很簡單的過程,對于解釋執行語言,肯定不會編譯成什么中間語言。(我認為)過程如下:
??? 首先,為執行環境(一個html也,框架環境下有幾個執行環境)建立建立一個全局對象,一般客戶端腳本為 window或global對象。(在這我覺得global好理解,因為瀏覽器會放入window總其他的屬性)
??? 然后,檢查某環境中根代碼塊中(非函數或{}中)var關鍵字,把這些變量設置成global對象的屬性,并附初值undefined.
?? 如果過程中遇到直接定義的函數(fun1的定義),那么把fun1設置成global對象的屬性,并附初值函數的定義(你可以把函數當成undefined,true,1,'1'等數據類型)。
b、解釋執行過程
?? 代碼按照順序執行,
?? 一般我們把全局變量的俯值放到代碼最前面,如var s="hello";? 那么把s的值用 'hello'替換預編譯過程的undefined。
?? 如果遇到變量的應用,如代碼? document.writeln(a),如果我們在global找到屬性a,看a是否在前面代碼俯值過,如果沒有,a的值為預編譯的undefined。如果是隱式變量聲明,在這把它添加到global的屬性中去。
?? 如果遇到類似var fun=function(){}; 把函數當成數據賦值給變量fun.
c、函數的調用過程
?? 你運行一下以下代碼,為什么結果是 test undefined local

< SCRIPT?LANGUAGE = " JavaScript " >
var ?s = " golbe " ;
function ?fun(s) {
????document.writeln(s);
????document.writeln(a);
????
var ?s = " local " ;
????
var ?a = "" ;
????
return ?s;
}

document.writeln(fun(
" test " ));
</ SCRIPT >

?

首先:預編譯代碼,把s、fun設置為golbe的屬性,并賦值s=undefined,fun=函數定義(可以直接調用)。
然后:按照順序解釋執行代碼。賦值s="golbe";?? 函數已經可以直接調用了。
執行函數:當運行到fun("test")時,開始函數調用。
?????? 先為本次調用建立一個調用對象(fun-global)。
?????? 預編譯函數體內代碼,把參數設置為fun-global的屬性,值為為傳入值"test",查找var,把a設置成fun-global的屬性,值為undefined.(如果var s與參數名稱相同,則不重復設置例如函數體內var s="local";)
????? 按照順序執行函數內代碼,當代碼中遇到變量,先從調用對象屬性中查找,如果找到直接使用。遇到var s="local";時,代碼會覆蓋調用對象中屬性值(和參數名稱相同)

調用對象是個暫時對象,生命周期很短,只有在調用過程中存在,遞歸可能會建立多個獨立的調用對象。
javascript的函數應該和java中一樣是線程安全的吧。
?

5、函數的屬性和方法
a、length
看了以下代碼一目了然,函數的length代表函數實際需要的參數個數。

< SCRIPT?LANGUAGE = " JavaScript " >
function ?add(x,y) {
????
var ?actual = arguments.length;
????
var ?expected = arguments.callee.length;
????
if (actual != expected) {
????????
throw ? new ?Error('函數需要' + expected + '個參數,你輸入了' + actual + '個');
????}

????
return ?x + y;
}

alert(add(
3 , 2 ));
alert(add(
3 , 2 , 3 ));
</ SCRIPT >

b、prototype
這個屬性引用的是預定義的原型對象,只有在new 函數名 才有效。講解對象時介紹。
c、定義自己的函數屬性

< SCRIPT?LANGUAGE = " JavaScript " >
add.count
= 0 ;
function ?add(x,y) {
????add.count
++ ;
????
return ?x + y;
}

add(
3 , 2 );
add(
3 , 2 );
add(
3 , 2 );
add(
3 , 2 );
document.writeln('共調用函數幾次:'
+ add.count);
</ SCRIPT >


d、apply() call()方法
去讀讀prototype.js吧。