閑聊js中的apply、call和arguments
JavaScript提供了apply和call兩種調用方式來確定函數中的this的指向,在現實編碼中,我確實
很少接觸到這兩個方法。但很無奈,很多面試題都要考這兩種方法,我又沒怎麽用到,所以我們先來
閑聊下他們到底有什麽用和到底怎麽用。
我們先來聊一下apply的用法吧,它是用來改變函數的指向的,說白了,就是指向了別的函數的作用域。
例如看一下下面這個例子。
var A={ name:"我是小A", fun:function(){ console.log("大家好! "+this.name) } }var B = { name:"我是小B" } A.fun(); //大家好! 我是小A A.fun.apply(B); //大家好! 我是小B
可以看出來,當我們使用了apply將引用指向了B時,A調用fun時並不是調用本身中的name 而是調用了B中的那麽;
但如果我們在調用函數中並沒用引用到this,那麽是不是說apply就失去了意義?再來看一下下面的例子
var A={ name:"我是小A", fun:function(num,money){ console.log("大家好! "+this.name+" 我有"+num+"張"+money+"塊") } } var B = { name:"我是小B" } var monies = [10,20]; A.fun.apply(B,monies); //大家好! 我是小B 我有10張20塊
可以看出:apply中
第一個參數為thisObject,調用時采用傳入的thisObject代替函數體中this的指向
第二個參數傳入一個數組,函數會用數組的值取代“參數列表"。
這裏聊一下monies,就要說到參數列表,當然我們會想到arguments,在這裏插入聊一下arguments。網
上arguments是具有數組某些特性的‘類數組‘(偽數組);其實JS並沒有重載函數的功能,但是auguments對象
能夠模擬重載。每個函數都有一個Arguments對象實例arguments,它引用著函數的實參,可以用數組下
標的方式”[]“引用arguments的元素。arguments.length為函數實參個數。
function test() {
var s = "";
for (var i = 0; i < arguments.length; i++) {
alert(arguments[i]);
s += arguments[i] + ",";
}
return s;
}
test("name", "age")
輸出
name,age
在匿名函數中可以用arguements.callee引用函數自身。
例如 function(){
if(n>0) return 0;
else return n+arguments.callee(n+1);
}
回歸正題,我們可以用arguments來代替函數中的參數
var A={ name:"我是小A", fun:function(num,money){ console.log("大家好! "+this.name+" 我有"+arguments[0]+"張"+arguments[1]+"塊") } } var B = { name:"我是小B" } var monies = [10,20]; A.fun.apply(B,monies); //大家好! 我是小B 我有10張20塊
這裏又有一個問題,可不可以用Array.prototype.shift.apply(arguments)來代替arguments[0]呢?直接看代碼
var A={ name:"我是小A", fun:function(num,money){ console.log("大家好! "+this.name+" 我有"+Array.prototype.shift.apply(arguments)+"張"+arguments[1]+"塊") } } var B = { name:"我是小B" } var monies = [10,20]; A.fun.apply(B,monies); //大家好! 我是小B 我有10張20塊
當我們使用Array.prototype.shift.apply(arguments)調用之後,arguments[0]就會被抹去,所以arguments[1]就會冒到arguments[0]上。
這可以看出arguments這個”偽數組“,除了不是”原型繼承自’Array.prototype‘“職位,其他特征和數組是一樣的。
最後,我們考慮一下,如果使用apply方法時,傳入的第一個參數是null時,調用函數時,會發生什麽情況,會不會報錯呢!
不多說,直接上例子
var A={ name:"我是小A", fun:function(num,money){ console.log("大家好! "+this.name+" 我有"+num+"張"+money+"塊") } } var B = { name:"我是小B" } var monies = [10,20]; name="我是小C" A.fun.apply(null,monies); //大家好! 我是小C 我有10張20塊
可以看到 如果第一傳入的參數是null的話,在函數提內的this會指向全局對象,在瀏覽器中就是window。
所以可以總結出兩點:
1.如果函數中有明確使用this,那麽this就會指向傳入的第一個參數的作用域。
2.如果傳入的第一參數為null時,this就會指向全局的作用域。
apply的另一種用法就是用於將數組分割為一個個元素。
例如想在數組中a[1,2,3,4]中尋找出最大的袁術出來。
如果直接調用Math.max(a);就會輸出NaN,所以這時候我們可以這樣
Math.max.apply(null,a); //輸出4
聊完了apply之後,我們再聊一下call就更簡單了,其實他們的作用都是一樣的。他們唯一的區別就是
apply和call在形式參數上的不同,apply只能傳入兩個參數且,第二個參數傳入的是數組,而call在
第二參數開始可以接受任意個參數。大家看下面的例子就一目了然了
var A={ name:"我是小A", fun:function(num,money){ console.log("大家好! "+this.name+" 我有"+num+"張"+money+"塊") } } var B = { name:"我是小B" } var monies = [10,20]; A.fun(monies[0],monies[1]); //大家好! 我是小A 我有10張20塊 A.fun.apply(B,monies); //大家好! 我是小B 我有10張20塊 A.fun.call(B,monies); //大家好! 我是小B 我有10,20張undefined塊 A.fun.call(B,monies[1],monies[2]); //大家好! 我是小B 我有20張undefined塊
閑聊js中的apply、call和arguments