apply()與call()的區別
想要深入了解 call()
和 apply()
這兩個方法,那麽必須要先知道他們的基本作用:
改變對象的執行上下文
什麽是執行上下文?
我們在寫一個方法的時候,總是會用到一個關鍵字this
,而this
的指向就是我們這裏所說的執行上下文(執行環境)
首先我們要知道,this
指向的永遠是調用該方法的對象,如何證明this
的指向就是當前對象呢?看下面這段代碼:
function func () {
this.a = 1;
console.log(this.a);
}
func(); // 1
代碼中方法執行後控制臺輸出1
,由於func
是全局對象window
下的一個方法,那麽調用該方法的對象就應該是全局對象window
this
理論上指向的對象就應該是window
如果理論成立,而this.a==1
,也就是說變量a
是一個全局變量。在控制臺上直接輸入a
或window.a
後回車,會發現輸出了1
,所以在func
這個方法中,this
的指向就是window
換個方式來驗證下:
var person = { name: ‘xiao ming‘, age: 18, who: function () { console.log( ‘my name is ‘ + this.name + ‘ , ‘ + this.age + ‘ years old‘ ); console.log( person === this); } } person.who(); // my name is xiao ming , 18 years old // true
上面這段代碼中who
方法是person
對象的一個屬性,被person
對象調用,所以this
的指向也就是person
call()
與apply()
異同
在了解異同之前,先來搞清楚這兩個方法都是怎麽用的
基本使用
call()
function.call(obj[,arg1[, arg2[, [,.argN]]]]])
- 調用
call
的對象必須是個函數function call
的第一個參數將會是function改變上下文後指向的對象,如果不傳,將會默認是全局對象window
- 第二個參數開始可以接收任意個參數,這些參數將會作為function的參數傳入function
- 調用
call
的方法會立即執行
apply()
function.apply(obj[,argArray])
與call
方法的使用基本一致,但是只接收兩個參數,其中第二個參數必須是一個數組或者類數組,這也是這兩個方法很重要的一個區別
數組與類數組小科普
數組我們都知道是什麽,它的特征都有哪些呢?
- 可以通過角標調用,如
array[0]
- 具有長度屬性
length
- 可以通過 for 循環和
forEach
方法進行遍歷
類數組顧名思義,具備的特征應該與數組基本相同,那麽可以知道,一個形如下面這個對象的對象就是一個類數組
var arrayLike = {
0: ‘item1‘,
1: ‘item2‘,
2: ‘item3‘,
length: 3
}
類數組arrayLike
可以通過角標進行調用,具有length
屬性,同時也可以通過 for 循環進行遍歷
我們經常使用的獲取dom節點的方法返回的就是一個類數組,在一個方法中使用 arguments
關鍵字獲取到的該方法的所有參數也是一個類數組
但是類數組卻不能通過forEach
進行遍歷,因為forEach
是數組原型鏈上的方法,類數組畢竟不是數組,所以無法使用
那麽如何才能讓類數組能夠使用forEach
呢?小夥伴們可以在看完本篇後自己思考一下哦
異同
相同點
都能夠改變方法的執行上下文(執行環境),將一個對象的方法交給另一個對象來執行,並且是立即執行
不同點
call
方法從第二個參數開始可以接收任意個參數,每個參數會映射到相應位置的func的參數上,可以通過參數名調用,但是如果將所有的參數作為數組傳入,它們會作為一個整體映射到func對應的第一個參數上,之後參數都為空
function func (a,b,c) {}
func.call(obj, 1,2,3)
// function接收到的參數實際上是 1,2,3
func.call(obj, [1,2,3])
// function接收到的參數實際上是 [1,2,3],undefined,undefined
apply
方法最多只有兩個參數,第二個參數接收數組或者類數組,但是都會被轉換成類數組傳入func中,並且會被映射到func對應的參數上
func.apply(obj, [1,2,3])
// function接收到的參數實際上是 1,2,3
func.apply(obj, {
0: 1,
1: 2,
2: 3,
length: 3
})
// function接收到的參數實際上是 1,2,3
兩個方法該如何選擇?
跟簡單,根據你要傳入的參數來做選擇,不需要傳參或者只有1個參數的時候,用call
,當要傳入多個對象時,用apply
或者,如果需要傳入的參數已經是一個數組或者類數組了,就用apply
,如果還是單獨的需要逐個傳入的,可以考慮使用call
(如果你不嫌麻煩的話 )
【其他用途——對象繼承】
由於可以改變this
的指向,所以也就可以實現對象的繼承
function superClass () {
this.a = 1;
this.print = function () {
console.log(this.a);
}
}
function subClass () {
superClass.call(this);
this.print();
}
subClass();
// 1
subClass
通過call
方法,繼承了superClass
的print
方法和a
變量,同時subClass
還可以擴展自己的其他方法
apply()與call()的區別