這三個方法的作用基本上相同,用法上有一些不同,下面先對比一下它們的用法:
- apply:調用一個具有給定 this 值的函數,以及以一個數組(或一個類數組對象)的形式提供的參數。
語法:
apply(thisArg)
apply(thisArg, argsArray)
- bind:創建一個新的函數,在 bind() 被調用時,這個新函數的 this 被指定為 bind() 的第一個參數,而其余參數將作為新函數的參數,供調用時使用。
語法:
function.bind(thisArg[, arg1[, arg2[, ...]]])
- call:使用一個指定的 this 值和單獨給出的一個或多個參數來調用一個函數。
語法:
function.call(thisArg, arg1, arg2, ...)
舉個例子說明一下:
三個方法解決同樣的問題:
JavaScript 新手經常犯的一個錯誤是將一個方法從對象中拿出來,然后再調用,期望方法中的 this 是原來的對象(比如在回調中傳入這個方法)。如果不做特殊處理的話,一般會丟失原來的對象。
代碼:
apply:
<script>this.x = 9; // 在瀏覽器中,this 指向全局的 "window" 對象var module = {x: 81,getX: function (y) {return this.x+':'+y;},};var module02 = {x: 91};console.log(module.getX(1));var retrieveX = module.getX;console.log(retrieveX(1));// 返回 9:1 - 因為函數是在全局作用域中調用的// 把 'this' 綁定到 module 對象var boundGetX = retrieveX.apply(module,[1]);console.log(boundGetX); // 81:1// 把 'this' 綁定到 module02對象,module02繼承了getXvar boundGetX2 = retrieveX.apply(module02,[1]);console.log(boundGetX2); // 81:1
</script>
輸出結果:
bind:
<script>this.x = 9; // 在瀏覽器中,this 指向全局的 "window" 對象var module = {x: 81,getX: function () {return this.x;},};console.log(module.getX());// 81var retrieveX = module.getX;console.log(retrieveX());// 返回 9 - 因為函數是在全局作用域中調用的// 創建一個新函數,把 'this' 綁定到 module 對象// 新手可能會將全局變量 x 與 module 的屬性 x 混淆var boundGetX = retrieveX.bind(module);console.log(boundGetX()); // 81
</script>
輸出結果:
call:
<script>this.x = 9; // 在瀏覽器中,this 指向全局的 "window" 對象var module = {x: 81,getX: function (y) {return this.x+':'+y;},};var module02 = {x: 91};console.log(module.getX(1));var retrieveX = module.getX;console.log(retrieveX(1));// 返回 9:1 - 因為函數是在全局作用域中調用的// 把 'this' 綁定到 module 對象var boundGetX = retrieveX.call(module,1);console.log(boundGetX); // 81:1// 把 'this' 綁定到 module02對象var boundGetX2 = retrieveX.call(module02,1);console.log(boundGetX2); // 81:1
</script>
輸出結果:
從上面的例子可以看出,apply與call基本相同,區別是apply的第二個參數是傳數組,而call是傳一個或多個參數。bind的區別是調用時要加(),它返回的是一個函數。三者的作用都是為方法指定this的值。
用例:
1、apply用數組獲取最大最小值
const numbers = [5, 6, 2, 3, 7];const max = Math.max.apply(null, numbers);console.log(max);
// Expected output: 7const min = Math.min.apply(null, numbers);console.log(min);
// Expected output: 2
ES6 的寫法:...
擴展運算符
Math.max(...[14, 3, 77])
2、將一個數組放到另外一個數組后面
// ES5 的寫法
var arr1 = [0, 1, 2];
var arr2 = [3, 4, 5];
Array.prototype.push.apply(arr1, arr2);// ES6 的寫法
let arr1 = [0, 1, 2];
let arr2 = [3, 4, 5];
arr1.push(...arr2);
3、使用 call 方法調用匿名函數
在下例中的 for 循環體內,創建了一個匿名函數,然后通過調用該函數的 call 方法,將每個數組元素作為指定的 this 值執行了那個匿名函數。這個匿名函數的主要目的是給每個數組元素對象添加一個 print 方法,這個 print 方法可以打印出各元素在數組中的正確索引號。當然,這里不是必須得讓數組元素作為 this 值傳入那個匿名函數(普通參數就可以),目的是為了演示 call 的用法。
var animals = [{ species: "Lion", name: "King" },{ species: "Whale", name: "Fail" },
];for (var i = 0; i < animals.length; i++) {(function (i) {this.print = function () {console.log("#" + i + " " + this.species + ": " + this.name);};this.print();}).call(animals[i], i);
}