建議59:推薦動态調用函數
調用函數更便捷的方式是使用Function對象的call和apply方法。apply與call方法在本質上沒有太大差別,隻不過它們傳遞給函數的參數方式不同, apply是以數組形式進行參數傳遞,而call方法可以同時傳遞多個值。
如果某個函數僅能夠接收多個參數清單,而現在希望把一個數組的所有元素作為參數進行傳遞,那麼使用apply方法就顯得非常便利。
function max(){
}
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(){
function b(){
function c(){
function f(){
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 e(){
e() //字元串a
上面的示例說明,如果在函數體内使用call和apply方法動态調用外部函數,并把call和apply方法的第一個參數值設定為關鍵字this,那麼目前函數e将繼承函數f的所有成員。使用call和apply方法能夠複制調用函數的内部變量給目前函數體,更改了函數f的内部關鍵字this指向函數e,這樣函數e就可以引用函數f的内部成員。
最後,再看一個比較複雜的示例。在這個示例中将示範如何使用apply方法循環更改目前指針,進而實作循環更改函數的結構。
function r( x ){
function f( x ){
function o(){
for( var i = 0 ; i < 10; i ++ ){
執行上面代碼後會看到,提示資訊框中的提示資訊不斷變化。該示例的核心就在于函數o的設計。在這個函數中,首先使用一個臨時變量存儲函數r。然後修改函數r的結構,在修改的函數r的結構中,通過調用apply方法修改原來函數r的指針指向目前對象,同時執行原函數r,并把執行函數f的值傳遞給它,進而實作修改函數r的return語句的後半部分資訊,即為傳回值增加一個字首字元“=”。這樣每次調用函數o時,都會為其增加一個字首字元“=”,進而形成一種動态的變化效果。
當然,call和apply方法的應用是非常靈活的,在大型JavaScript技術架構中經常會用到它們,利用它們可以實作動态更改對象的指針,進而實作各種複雜的功能。