關於call和apply,以前也思考良久,很多時候都以為記住了,但是,我太難了。今天我特地寫下筆記,希望可以完全掌握這個東西,也希望可以幫助到任何想對學習這個東西的同學。 一.apply函數定義與理解,先從apply函數出發 在MDN上,apply的定義是: “apply()方法調用一個具有給定th ...
關於call和apply,以前也思考良久,很多時候都以為記住了,但是,我太難了。今天我特地寫下筆記,希望可以完全掌握這個東西,也希望可以幫助到任何想對學習這個東西的同學。
一.apply函數定義與理解,先從apply函數出發
在MDN上,apply的定義是:
“apply()
方法調用一個具有給定this
值的函數,以及作為一個數組(或類似數組對象)提供的參數。”
我的理解是:apply的前面有個含有this的對象,設為A,apply()的參數里,也含有一個含有this的對象設為B。則A.apply(B),表示A代碼執行調用了B,B代碼照常執行,執行後的結果作為apply的參數,然後apply把這個結果所指代表示的this替換掉A本身的this,接著執行A代碼。
比如:
1 var aa = { 2 _name:111, 3 _age:222, 4 _f:function(){ 5 console.log(this) 6 console.log(this._name) 7 } 8 } 9 var cc = { 10 _name:0, 11 _age:0, 12 _f:function(){ 13 console.log(this) 14 console.log(this._name) 15 } 16 } 17 cc._f.apply(aa)//此時aa表示的this就是aa本身 18 cc._f.apply(aa._f)//此時aa._f表示的this就是aa._f本身 19 20 /** 21 * 此時aa._f()表示的this,就是執行後的結果本身。aa._f()執行後,沒有返回值,所以應該是undefined,而undefined作為call和apply的參數時,call和apply前面的方法 cc._f 的this會替換成全局對象window。 22 * 參考MDN:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Function/apply 的參數說明 23 */ 24 cc._f.apply(aa._f())
執行結果:
1.參數為aa
這兩行的列印的都是來自 cc._f 方法內的那兩句console 。aa的時候算是初始化,裡面的 aa._f 方法沒有執行。
2.參數為aa.f
這兩行的列印的都是來自 cc._f 方法內的那兩句console 。aa.f 的時候應該也算是初始化,或者是整個函數當參數傳但是不執行這個參數,即 aa._f 方法沒有執行。
3.參數為aa.f()
這四行的列印,前面兩行來自 aa._f() 方法執行列印的;後面兩行是來自cc._f()方法列印的。
後兩行解析:aa._f()執行後,沒有返回值,所以是undefined,在apply執行解析後,cc._f()的this變成的window,所以列印了window。window裡面沒有_name這個屬性,所以undefined。
二.apply與call的區分
1.apply()
A.apply(B, [1,2,3]) 後面的參數是arguments對象或類似數組的對象,它會被自動解析為A的參數;
對於A.apply(B) / A.call(B) , 簡單講,B先執行,執行後根據結果去執行A。這個時候,用A去執行B的內容代碼,然後再執行自己的代碼。
比如:
var f1 = function(a,b){ console.log(a+b) } var f2 = function(a,b,c){ console.log(a,b,c) } f2.apply(f1,[1,2])//1 2 undefined
先執行f1,f1執行後(f1是f1,不是f1()執行方法,所以console.log(a+b)這行代碼並沒有執行,相當於,初始化了代碼f1),由於沒有返回值,所以結果是undefined,f2執行的時候this指向window;參數中的 ” [1,2] “,解析後變成 f2 的參數 “ 1,2,undefined ”,執行f2方法後,列印出1,2,undefined三個值
2.call()
A.call(B, 1,2,3) 後面的參數都是獨立的參數對象,它們會被自動解析為A的參數;
比如:
var f1 = function(a,b){ console.log(a+b) } var f2 = function(a,b,c){ console.log(a,b,c) } f2.call(f1,[1,2])//[1,2] undefined undefined f2.call(f1,1,2)//1 2 undefined
參數中的 ” [1,2] “,因為傳入了一個數組,相當於只傳入了第一個參數,b和c參數沒有傳。解析後變成 f2 的參數 “ [1,2],undefined ,undefined ”,執行f2方法後,列印出 [1,2],undefined ,undefined 三個值。
三.apply與call帶來的便利
1. push();
push參數是類似(a,b,c,d,e)如此傳輸的,如果在一個數組的基礎上進行傳輸另一個數組的內容,可以如下:
//apply用法 var arr = new Array(1,2,3) var arr1 = new Array(11,21,31) Array.prototype.push.apply(arr,arr1) console.log(arr)//[1, 2, 3, 11, 21, 31] //call用法 var arr = new Array(1,2,3) var arr1 = new Array(11,21,31) Array.prototype.push.call(arr,arr1[0],arr1[1],arr1[2]) console.log(arr)//[1, 2, 3, 11, 21, 31]
2. 數組利用Math求最大和最小值
apply和call的第一個參數,如果是null或者undefined,則apply或call前面的函數會把this指向window
//apply的用法 var _maxNum = Math.max.apply(null,[1,3,2,4,5]) console.log(_maxNum)//5 var _minNum = Math.min.apply(null,[1,3,2,4,5]) console.log(_minNum)//1 //call的用法 var _maxNum = Math.max.call(null,1,3,2,4,5) console.log(_maxNum)//5 var _minNum = Math.min.call(null,1,3,2,4,5) console.log(_minNum)//1
四.總結
簡而言之,apply和call函數的第一個參數都是用來替換this指向的對象;apply的第二個參數使用arguments或者類似數組的參數進行傳參,call的第二個或以上的參數,使用獨立單位,一個一個進行傳參;執行順序是apply或call的第一個參數先執行得到結果,然後執行apply或call前面的函數,執行的時候用已經執行的結果所指代的this去執行。apply和call的使用除了參數上的使用方式不同外,功能是一模一樣的。
以上內容純屬個人理解,有誤勿噴請指出!謝謝!