JavaScript提供了apply和call兩種調用方式來肯定函數中的this的指向,在現實編碼中,我確實面試
不多接觸到這兩個方法。但很無奈,不少面試題都要考這兩種方法,我又沒怎麼用到,因此咱們先來數組
閒聊下他們到底有什麼用和到底怎麼用。
咱們先來聊一下apply的用法吧,它是用來改變函數的指向的,說白了,就是指向了別的函數的做用域。瀏覽器
例如看一下下面這個例子。app
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就失去了意義?再來看一下下面的例子this
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的指向spa
第二個參數傳入一個數組,函數會用數組的值取代「參數列表"。prototype
這裏聊一下monies,就要說到參數列表,固然咱們會想到arguments,在這裏插入聊一下arguments。網code
上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張undefined塊
當咱們使用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塊