說明白一點其實就是更改對象的內部指標,即改變對象的this指向的內容。這在物件導向的js編程過程中有時是很有用的。
call函數和apply方法的第一個參數都是要傳入給當前對象的對象,及函數內部的this。後面的參數都是傳遞給當前對象的參數。
對於apply和call兩者在作用上是相同的,但兩者在參數上有區別的。
對於第一個參數意義都一樣,但對第二個參數:
apply傳入的是一個參數數組,也就是將多個參數組合成為一個數組傳入,而call則作為call的參數傳入(從第二個參數開始)。
如 func.call(func1,var1,var2,var3)對應的apply寫法為:func.apply(func1,[var1,var2,var3])
同時使用apply的好處是可以直接將當前函數的arguments對象作為apply的第二個參數傳入。
(reference:http://www.cnblogs.com/beyondnet/archive/2007/12/06/985216.html)
TEST:
function cls1()
{
this.b='111';
this.c ='222';
this.d ='333';
this.f = function()
{
alert("nihao");
}
}
function cls2()
{
this.a='aaa';
cls1.apply(this); //這裡用的是類(也可直接看成函數)直接來apply的。不是用執行個體。此時,cls2類擁有 cls1類的所有屬性和方法.
}
var st = new cls2();
alert(st.d);
/*注意,這裡可以在第2個類中,用第一個類的名稱來實現所有屬性和方法的複製。方法可以用如下方法複製:ss.f.apply(this);可以正常運行。而屬性ss.c.apply(this);則會報錯,
function cls2()
{
this.a='aaa';
var ss = new cls1;
ss.c.apply(this); //這裡會報錯。如果為ss.f.apply(this);則正確。如果是屬性,則用類名,如果是方法,即 可用類名,也可用執行個體加方法的形式應該(var ss = new cls1;ss.f.apply(this);)
如下形式(***正確****)。
}
var st = new cls2();
alert(st.c);
****正確*******
function cls2()
{
this.a='aaa';
cls1.apply(this); //如果是屬性,則用類名,如果是方法,即可用類名,也可用執行個體加方法的形式
}
var st = new cls2();
alert(st.c);
_______________________________________________
function simpleApplyDemo(sim) {
this.sim_name = sim;
}
function handleSPA(hand) {
this.hand_name = hand ;
simpleApplyDemo.apply(this, new Array('222222222222')); //這裡用的是類名
////此處用Array()數組,是將這個數組的初始化值賦給simpleApplyDemo函數中的參數。也就是sim = 222222222222,在JS手冊中,apply([thisObj[,argArray]])的
argArra是可選項,解釋為將被傳遞給該函數的參數數組。(也就是說argArray同下的arguments是一樣的)
alert(this.sim_name);
}
handleSPA();
上面的方法和下面的方法實現的效果一樣
function simpleApplyDemo(sim) {
this.sim_name = sim;
}
function handleSPA(hand) {
this.hand_name = hand ;
simpleApplyDemo.apply(this,arguments); //這裡用的是類名
/* 此處用arguments,是將handleSPA('55555555')中5555555作為arguments(arguments代表本身的參數的集合,此處只代表5555555)將arguments傳到simpleApplyDemo()中,也就是sim = arguments =55555 */
alert(this.sim_name);
}
handleSPA('55555555');
call方法在msdn中的解釋 調用一個對象的一個方法,以另一個對象替換當前對象。
apply方法在msdn中的解釋 應用某一對象的一個方法,用另一個對象替換當前對象。
這個解釋也是非常抽象的,這兩個方法的作用基本是一樣的,舉個例子
<script>
function cls1()
{
this.a='123';
}
cls1.prototype.fun1=function()
{
alert(this.a);
}
function cls2()
{
this.a='456';
}
var o1=new cls1();
var o2=new cls2();
o1.fun1.apply(o2); //這裡用的是執行個體名,如果寫成 o1.apply(o2)則報錯
</script>
只有o1對象的類cls1中有fun1這個方法,但是,這時我們需要用o2對象替代o1對象,所以這個時候顯示的this.a會是456,呵呵很神奇吧,換成call方法也是一樣的,這兩種方法使用的不同點僅僅是參數的使用方法上不同,這裡就不多做解釋了。
大家可以在prototype.js裡看到
var Class = {
create: function() {
return function() {
this.initialize.apply(this, arguments);
}
}
}
這種代碼,相當的誇張,很多人很容易被這種bt的代碼弄糊塗,其實仔細分析其中的道理卻也不難
顯然這種寫法代表了Class是聲明的一個Object對象,其中create是這個object對象的一個屬性,這個屬性就是一個函數。這個函數執行過後返還一個函數。可能這樣解釋太複雜了,那不如做一個實驗好了。
<script>
var x=function(){return function(){alert(123);}}
var n=x();
n();
</script>
很好玩吧,這裡n就是x函數執行過後返還給的一個函數也就是n現在等於了function(){alert(123);}再執行n()的時候就跳出了123
現在開始講痛點 this.initialize.apply(this, arguments);
這句表達了什麼含義,其實現在先看看prototype.js裡怎麼調用的就明白了
var Template = Class.create();
Template.prototype = {
initialize: function(template, pattern) {
this.template = template.toString();
this.pattern = pattern || Template.Pattern;
},....省略代碼若干
var template = new Template(replacement);
第一句話Class.create(); 就是返還給Template 一個函數,這個函數是
function() {
this.initialize.apply(this, arguments);
}
當執行var template = new Template(replacement);時,就變成了要執行這個函數,而這個函數的作用是
執行當前類中initialize這個函數
所以prototype.js中的每一個類都預留了
Template.prototype = {
initialize: function(template, pattern) {
this.template = template.toString();
this.pattern = pattern || Template.Pattern;
},....
這麼個函數,如果沒有這個的話,程式將會出錯
知其然,知其所以然,為什麼要這麼寫呢?
一般我們聲明的時候funciton fun(){} var o=new fun();這樣感覺fun又是類又是建構函式很彆扭,為了分開這種不是很友好的代碼方案,所以prototype.js使用了如上方法