????? 在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吧。