匿名函數的概念大家也許不會陌生,但是我相信下面的內容會開啟一些新的思路。
我們知道函數的定義方式有兩種:
1 function fn1(){alert(‘fn1 works’);}
2 var fn2=function(){alert(‘fn2 works’);}
這兩種方式有什麼區別?思考一下…
1 第一種方式定義函數,函式宣告過程在整個程式執行之前的預先處理就完成了,所以只要處於同一個範圍,就可以訪問到,即使在定義之前調用它也可以。
2 第二章方式就是匿名函數,這種方式函數只能按照程式流程執行到定義的那一行代碼才被聲明,所以只能在定義之後調用它。
舉個例子
var fn1;
fn1();//報錯
fn1=function(){
fn2();//fn2 works
alert(‘fn1 works’);
return false;
function fn2(){
alert(‘fn2 works’);
}
}
fn1();//fn2 works + fn1 works
我們看到fn2雖然處在return之後,程式流程並沒有執行到它,但是它依然可以被使用,反之fn2隻有在它被定義之後才會被正常執行。
明白了這個,下面看一看匿名函數在遞迴裡用處
遞迴就是函數內部調用自己,舉個例子
function fn1(n){return n>2?fn1(n-1)+fn1(n-2):n;}
當我們想把這個函數賦給其他的對象屬性時,就要用到匿名函數,比如
obj1={
fn:function(n){
return n>2?obj1.fn(n-1)+obj1.fn(n-2):n;}}obj2={fn:obj.fn;}
這個時候可以正常調用obj2.fn(),但是這裡有一個隱患,我們必須保證obj1裡的fn不能被覆蓋,看下面的例子
obj1={}obj2.fn();
obj1被清空,執行出錯,怎麼辦,解決辦法有很多,自己先想一個…最容易的想到的是使用this,更改obj1裡面fn的定義如下
obj1={
fn:function(n){
return n>2?this.fn(n-1)+this.fn(n-2):n;}}
這樣即使obj1裡的fn被改寫也不影響obj2.fn(),但是this,你迷惑嗎?this在JavaScript裡面絕對是一個難理解的概念,理解了最好,但是很多時候其實不一定非得用this,這個例子中,我們可以選個給匿名函數添加個名字
obj1={
fn:function fnname(n){
return n>2?fnname(n-1)+fnname(n-2):n;}}
我們發現和this的結果一樣,但是這就避開了this的混淆視聽,而且注意這個函數名只有函數內部可以訪問,外部是訪問不了的(請私下測試),這樣就能避免諸如全域變數的問題。還有一種解決方案,這個方案是最優雅的,所以我要作為大禮送給大家我們知道有個arguments對象,這個對象裡面有好多好玩的屬性和方法,其中一個叫做callee,它的作用是調用函數本身!繼續修改上面的例子
obj1={
fn:function(n){
return n>2?arguments.callee(n-1)+arguments.callee(n-2):n;}}
這個是目前我發現最優雅的方法,大家有其他更好的方案可以拿來討論。匿名函數的討論先到此為止。轉載請註明:大前端 »
一家之言:談談JavaScript匿名函數