call() 和 apply() 的相關介紹和應用場景
- 2019 年 11 月 7 日
- 筆記
基本語法:
fun.call(thisArg, param1, param2, ...) fun.apply(thisArg, [param1,param2,...]) fun.bind(thisArg, param1, param2, ...)
返回值
call() 和 apply() 返回函數應該返回的值,bind() 返回一個經過硬綁定的新函數。
參數介紹:
第一個參數為 thisArg,其取值有以下幾種情況:
- 不傳/ 傳null/ 傳undefined:非嚴格模式下,this 指向 window 對象;嚴格模式下指向 undefined;
- 傳遞基本類型:this 指向其對應的包裝對象,如 String、Number、Boolean
- 傳遞一個對象:函數中的 this 指向這個對象
第二個參數有以下幾種情況:
- 不傳/ 傳null/ 傳undefined:表示不需要傳入任何參數
call()和bind()的第二個參數都是參數列表,而apply()則是參數數組(或者類數組)—— 儘管如此,在這些參數傳遞給調用函數時,仍然是以參數列表的形式傳遞的(這一點很重要)。
執行
call() 和 apply() 一經調用則立即執行函數,而 bind() 則只是完成了函數的 this 綁定。因為函數不會立刻執行,所以適合在事件綁定函數中使用 bind() ,這樣既完成了綁定,也確保了僅當事件觸發時才執行函數。
應用場景
在這篇文章說過,call(),apply() 和 bind() 都可以改變 this 的指向,什麼時候需要改變 this 的指向呢?大部分時候其實是為了借用方法,即在對象上調用其自身不具備的方法。看一下下面的例子:
1.判斷數據類型 利用 Object.prototype.toString.call() 可以準確地判斷數據類型,如:
var a = "abc"; var b = [1,2,3]; Object.prototype.toString.call(a) == "[object String]" //true Object.prototype.toString.call(b) == "[object Array]" //true
原理就是:在任何值上調用 Object 原生的 toString() 方法,都會返回一個格式為 [object NativeconstructorName] 的字元串。據此可以準確判斷任何值的數據類型。 既然 Array 和 Function 都繼承了 Object 的該方法,為什麼不直接在它們身上調用?這是因為 toString() 被重寫過了,不是原生方法,因此這裡改為調用 Object 的該方法,並將 this 綁定給對應的值。
2.模擬淺拷貝 模擬淺拷貝的過程中,需要剔除原型鏈上的屬性,考慮到源對象可能基於 Object.create() 創建,而這樣的對象是沒有 hasOwnProperty() 方法的,因此我們不在源對象身上直接調用該方法,而是通過 Object.prototype.hasOwnProperty.call() 的方式去調用,因為 Object 一定是有這個方法的,我們可以借用一下。
if (Object.prototype.hasOwnProperty.call(nextSource, nextKey)) { to[nextKey] = nextSource[nextKey]; }3.繼承 JavaScript 的幾種繼承方式中,有一種就是借用構造函數: 假設有子構造函數 Son 和父構造函數 Parent。對於 Son 而言,其內部的 this 將指向稍後實例化的對象,利用這一點,我們在 Son 的內部通過 call() 或者 apply() 調用 Parent,同時傳參 this,這樣就可以增強子類實例。
4.類數組借用數組的方法 例如 arguments 是類數組,並不具備數組的 forEach() 方法,那麼我們可以通過 call() 調用數組的該方法,同時將方法裡面的 this 綁定到 arguments 上:
Array.prototype.forEach.call(arguments,function(item){ console.log(item); });5.求數組的最值 核心是 apply() 可用於展開數組,即我們前面說過的將參數數組轉化為參數列表。 例如我們要求一個數組的最大值,雖然 Math 對象有 max() 方法,但該方法只接受參數列表。那麼這時候,我們可以通過 apply() 去調用該方法,從而展開數組
var arr = [2,3,1,5,4]; Math.max.apply(null,arr);// 5
參考: https://www.cnblogs.com/onepixel/p/6034307.html https://juejin.im/post/5d469e0851882544b85c32ef
