call和apply方法的異同
基本作用:改變對象的執行上下文。
this指向執行上下文。(執行環境)
this指向的永遠是調用該方法的對象
function func(){ this.a=1; console.log(this.a); }
代碼中方法執行後控制臺輸出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();
上面這段代碼中who
方法是person
對象的一個屬性,被person
對象調用,所以this
的指向也就是person。
function.call(obj, args1,args2,...)
- 調用
call
的對象必須是個函數function call
的第一個參數將會是function改變上下文後指向的對象,如果不傳,默認為全局對象window- 第二個參數開始可以接收任意個參數,這些參數將會作為function的參數傳入function
- 調用
call
的方法會立即執行
apply()
function.apply(obj,args[...])
只接收兩個參數,其中第二個參數必須是一個數組或者類數組,這也是這兩個方法很重要的一個區別
數組與類數組小科普
數組我們都知道是什麽,它的特征都有哪些呢?
- 可以通過角標調用,如
array[0]
- 具有長度屬性
length
- 可以通過 for 循環和
forEach
方法進行遍歷
類數組顧名思義,具備的特征應該與數組基本相同,那麽可以知道,一個形如下面這個對象的對象就是一個類數組
var arrayLike = { 0: ‘item1‘, 1: ‘item2‘, 2: ‘item3‘, length: 3 }
類數組arrayLike
可以通過角標進行調用,具有length
屬性,同時也可以通過 for 循環進行遍歷
我們經常使用的獲取dom節點的方法返回的就是一個類數組,在一個方法中使用 arguments
關鍵字獲取到的該方法的所有參數也是一個類數組
但是類數組卻不能通過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
還可以擴展自己的其他方法。
call和apply方法的異同