【註】:記錄自己對javascript中call與apply的見解
總會有些東西會被人拿出來重復的寫來寫去,為何?
隻是因為自己感覺不夠瞭解,所謂好記性不如爛筆頭,並且在寫的同時也會或多或少的收獲到一些額外的知識,這才是重點(但是必須用心去寫)
call 概念
【概念】:調用一個對象的一個方法,以另一個對象替換當前對象 或者(劫持另外一個對象的方法,繼承另外一個對象的屬性)
【函數】:Function.call(obj,[param1[,param2[,…[,paramN]]]])
【參數】:obj:“可選項。這個對對象將替代Function類裡面的this。”,param1, param2, , paramN:“可選項。將被傳遞方法參數序列。”
【說明】:call 方法可以用來代替另一個對象調用一個方法。call 方法可將一個函數的對象上下文從初始的上下文改變為由 obj 指定的新對象。如果沒有提供 obj參數,那麼 Global 對象被用作 obj
例子
復制代碼
var a = 1, b = 2; //申明全局變量a,b
var o = { a: 3, b: 4} //申明對象o
//打印出當前對象
function funCall() {
console.log(this);
}
funCall(); //直接調用–>this=window
funCall.call(); //調用funCall方法的call方法–>this=window
funCall.call(o); //以o作為參數調用funCall方法的call方法–>this=o
復制代碼
apply概念
【概念】:和call的意思一樣,隻不過是參數列表不一樣
【函數】:Function.apply(obj,args)
【參數】:obj:“可選項。這個對對象將替代Function類裡面的this。”,args:“可選項。這個是數組,它將作為參數傳給Function(args–>arguments)”
【說明】:和call的意思一樣,隻不過是參數列表不一樣
例子
復制代碼
var a = 1, b = 2; //申明全局變量a,b
var o = { a: 3, b: 4} //申明對象o
//打印出當前對象
function funApply() {
console.log(this);
}
funApply(); //直接調用–>this=window
funApply.apply(); //調用funApply方法的apply方法–>this=window
funApply.apply(o); //以o作為參數調用funApply方法的apply方法–>this=o
復制代碼
call與apply區別,以及什麼時候用call、什麼時候用apply
【this】首先說下我心中的this:哪個上下文對象調用對應的Function,Funtion中的this就是該上下文對象(Funtion中調用另外一個Funtion,this則會指向window,閉包瞭~~~~)
通過上述概念的介紹,可以看出call與apply的唯一區別在於參數列表(上述例子中隻調用瞭call與apply的一個參數的重載方法)
復制代碼
var a = 1, b = 2, c = 5; //申明全局變量a,b
var o = { a: 3, b: 4, e: 6} //申明對象o
//打印出當前對象
function funCallorApply() {
console.log(a);
console.log(b);
console.log(c);
console.log(this);
}
復制代碼
1,call的多參數調用
call多參數調用還蠻有趣的(至少我是這麼理解的),它和jQuery的extend有點相似
funCallorApply.call(o, a, b, c);
//結果:
//1
//2
//5
//Object {a: 3, b: 4, e: 6}
從上述的結果可以知道:call中的第一個參數對象會被替換成觸發方法的this,後續都會被當作參數進行傳遞
2,apply的多參數調用
apply則不像call可以代入多個參數,apply隻有2個參數,第二個參數需要以數組的形式存在,所以參數是以對象數組的方式進行傳遞。
funCallorApply.apply(o, [a, b, c]);
//結果
//1
//2
//5
//Object {a: 3, b: 4, e: 6}
從上述結果可以知道:apply和call一樣第一個參數對象會被替換被替換成觸發方法的this,不通的是參數傳遞的方式
3,什麼時候用call,什麼時候用apply
其實我一般用的是apply,它可以將參數以對象數組的方式傳遞(因為我喜歡這種方式傳遞參數,因為這樣可以在方法中設置默認值,然後通過extend繼承去重新默認值)。
理論說來要看你方法是怎麼構造的瞭
復制代碼
//方法是這樣就可以考慮使用call
function funCallorApply(a, b, c) {
this.a = a;
this.b = b;
this.c = c;
//具體的實現
}
funCallorApply.call(o, a, b, c);
//方法是這樣可以考慮使用apply
function funCallorApply(obj) {
this.a = obj.a;
this.b = obj.b;
this.c = obj.c;
//具體的實現
}
funCallorApply.apply(o, [a, b, c]);
復制代碼
一般為瞭方法的擴展,將參數以數組的形式進行傳遞是個不錯的方式。如果需要改參數就不需要去動其它調用的地方瞭。
apply的額外補充
在紫雲飛的文章中發現瞭一點apply的額外用處(學淺,隻能把第一個運用到實際開發中尷尬)
細心的人可能已經察覺到,在我調用apply方法的時候,第一個參數是對象(this),第二個參數是一個數組集合。
在調用funCallorApply.apply(o, [a, b, c])的時候,第二參數是一個數組,但是為什麼我仍然可以將數組解析為一個一個的參數?
這個就是apply的一個巧妙的用處,可以將一個數組默認的轉換為一個參數列表([param1,param2,param3] 轉換為 param1,param2,param3) ,這個如果讓我們用程序來實現將數組的每一個項,來裝換為參數的列表,可能都得費一會功夫,借助apply的這點特性,所以就有瞭以下高效率的方法:
1,獲取數組中的最大值通過Math.max
//JavaScript中沒有返回一個數組中最大值的函數.但是,有一個函數Math.max可以返回任意多個數值類型的參數中的最大值.再配合apply,我們可以實現我們的目的
Math.max.apply(null, [3, 8, 10, -1, 5]); //結果–>10
Math.min最小值也一樣應用
2,數組合並
//同樣push方法沒有提供push一個數組,但是它提供瞭push(param1,param,…paramN) 所以同樣也可以通過apply來裝換一下這個數組
var arr1 = new Array("1", "2", "3");
var arr2 = new Array("4", "5", "6");
Array.prototype.push.apply(arr1, arr2);
Array.prototype.push.apply會返回合並後數組的length,上面結果是6,合並之後arr1就變成瞭["1", "2", "3", "4", "5", "6"]