讀古今文學網 > 編寫高質量代碼:改善JavaScript程序的188個建議 > 建議59:推薦動態調用函數 >

建議59:推薦動態調用函數

調用函數更便捷的方式是使用Function對象的call和apply方法。apply與call方法在本質上沒有太大區別,只不過它們傳遞給函數的參數方式不同,apply是以數組形式進行參數傳遞,而call方法可以同時傳遞多個值。

如果某個函數僅能夠接收多個參數列表,而現在希望把一個數組的所有元素作為參數進行傳遞,那麼使用apply方法就顯得非常便利。


function max{

var m=Number.NEGATIVE_INFINITY;//聲明一個負無窮大的數值

for(var i=0;i<arguments.length;i++){

if(arguments[i]>m)

m=arguments[i];

}

return m;

}

var a=[23,45,2,46,62,45,56,63];

var m=max.apply(Object,a);

alert(m);//63


在上面的示例中,首先定義一個函數來計算所傳遞實參的最大值。由於該函數僅能夠接收多個數值參數,所以通過apply方法動態調用max函數,然後把它綁定為Object對象的一個方法,並藉機把一個數組傳遞給它,最後返回此函數的運行值。如果沒有apply方法,想使用max函數來計算數組中最大元素值,就需要把數組的所有元素讀取出來,然後再傳遞給函數,顯然這種做法是費力不討好的。

實際上,也可以把數組元素通過apply方法傳遞給系統對像Math的max方法來計算數組的最大元素值。


var a=[23,45,2,46,62,45,56,63];//聲明並初始化數組

var m=Math.max.apply(Object,a);//調用系統函數max

alert(m);//63


使用call和apply方法可以把一個函數轉換為方法傳遞給某個對象。這種行為只是臨時的,函數最終並沒有作為對象的方法而存在,當函數被調用後,該對像方法會自動被註銷。下面的示例具體地說明了這種行為。


function f{}

f.call(Object);

Object.f;


call和apply方法能夠更改對象的內部指針,即改變對象的this指向的內容,這在面向對象的編程過程中是非常有用的。


var x=\"o\";

function a{

this.x=\"a\";

}

function b{

this.x=\"b\";

}

function c{

alert(x);

}

function f{

alert(this.x);

}

f;//字符o,即全局變量x的值。this此時指向window對像

f.call(window);f.call(new a);//字符a,即函數a內部的局部變量x的值。this此時指向函數a

f.call(new b);//字符b,即函數b內部的局部變量x的值。this此時指向函數b

f.call(c);/*undefined,即函數c內部的局部變量x的值,但是該函數並沒有定義x變量,所以返回沒有定義。this此時指向函數c*/


通過上面示例的比較,能夠很直觀地發現,函數f內部的this關鍵字會隨著所綁定的對象不同而指向不同的對象。因此,利用call或apply方法能夠改變函數內部指針指向所綁定的對象,從而實現屬性或方法繼承。


function f{

this.a=\"a\";

this.b=function{

alert(\"b\");

}

}

function e{

f.call(this);

alert(a);

}

e//字符串a


上面的示例說明,如果在函數體內使用call和apply方法動態調用外部函數,並把call和apply方法的第一個參數值設置為關鍵字this,那麼當前函數e將繼承函數f的所有成員。使用call和apply方法能夠複製調用函數的內部變量給當前函數體,更改了函數f的內部關鍵字this指向函數e,這樣函數e就可以引用函數f的內部成員。

最後,再看一個比較複雜的示例。在這個示例中將演示如何使用apply方法循環更改當前指針,從而實現循環更改函數的結構。


function r(x){

return(x);

}

function f(x){

x[0]=x[0]+\">\";

return x;

}

function o{

var temp=r;

r=function{

return temp.apply(this,f(arguments));

}

}

function a{

o;

alert(r(\"=\"));

}

for(var i=0;i<10;i++){

a;

}


執行上面代碼後會看到,提示信息框中的提示信息不斷變化。該示例的核心就在於函數o的設計。在這個函數中,首先使用一個臨時變量存儲函數r。然後修改函數r的結構,在修改的函數r的結構中,通過調用apply方法修改原來函數r的指針指向當前對象,同時執行原函數r,並把執行函數f的值傳遞給它,從而實現修改函數r的return語句的後半部分信息,即為返回值增加一個前綴字符「=」。這樣每次調用函數o時,都會為其增加一個前綴字符「=」,從而形成一種動態的變化效果。

當然,call和apply方法的應用是非常靈活的,在大型JavaScript技術框架中經常會用到它們,利用它們可以實現動態更改對象的指針,從而實現各種複雜的功能。