apply、call
在 javascript 中,call 和 apply 都是為了改變某個函式運行時的背景關系(context)而存在的,換句話說,就是為了改變函式體內部 this 的指向,
JavaScript 的一大特點是,函式存在「定義時背景關系」和「運行時背景關系」以及「背景關系是可以改變的」這樣的概念,
先來一個栗子:
function fruits() {}
fruits.prototype = {
color: "red",
say: function() {
console.log("My color is " + this.color);
}
}
var apple = new fruits;
apple.say(); //My color is red
但是如果我們有一個物件banana= {color : “yellow”} ,我們不想對它重新定義 say 方法,那么我們可以通過 call 或 apply 用 apple 的 say 方法:
banana = {
color: "yellow"
}
apple.say.call(banana); //My color is yellow
apple.say.apply(banana); //My color is yellow
所以,可以看出 call 和 apply 是為了動態改變 this 而出現的,當一個 object 沒有某個方法(本栗子中banana沒有say方法),但是其他的有(本栗子中apple有say方法),我們可以借助call或apply用其它物件的方法來操作,
apply、call 的區別
對于 apply、call 二者而言,作用完全一樣,只是接受引數的方式不太一樣,例如,有一個函式定義如下:
var func = function(arg1, arg2) {
};
就可以通過如下方式來呼叫:
func.call(this, arg1, arg2);
func.apply(this, [arg1, arg2])
其中 this 是你想指定的背景關系,他可以是任何一個 JavaScript 物件(JavaScript 中一切皆物件),call 需要把引數按順序傳遞進去,而 apply 則是把引數放在陣列里,
JavaScript 中,某個函式的引數數量是不固定的,因此要說適用條件的話,當你的引數是明確知道數量時用 call ,
而不確定的時候用 apply,然后把引數 push 進陣列傳遞進去,當引數數量不確定時,函式內部也可以通過 arguments 這個偽陣列來遍歷所有的引數,
bind
bind 和 call/apply 有一個很重要的區別,一個函式被 call/apply 的時候,會立即執行函式,但是 bind 會創建一個新函式,不會立即執行,
var obj = {
x: 81,
};
var foo = {
getX: function() {
return this.x;
}
}
console.log(foo.getX.bind(obj)()); //81
console.log(foo.getX.call(obj)); //81
console.log(foo.getX.apply(obj)); //81
三個輸出的都是81,但是注意看使用 bind() 方法的,他后面多了對括號,也就是說,區別是,當你希望改變背景關系環境之后并非立即執行,而是回呼執行的時候,使用 bind() 方法,而 apply/call 則會立即執行函式,
當這個新函式被呼叫時,bind() 的第一個引數將作為它運行時的 this,傳入 bind() 方法的第二個以及以后的引數加上系結函式運行時本身的引數按照順序作為原函式的引數來呼叫原函式,
如上,bind另一個重要的區別是,后面傳入的這個引數串列可以分多次傳入,call和apply則必須一次性傳入所有引數,
示例:
var arr=[1,10,5,8,12];
var max=Math.max.bind(null,arr[0],arr[1],arr[2],arr[3])
console.log(max(arr[4])); //12,分兩次傳參
可以看出,bind方法可以分多次傳參,最后函式運行時會把所有引數連接起來一起放入函式運行,
應用場景
陣列之間追加
var array1 = [12 , "foo" , {name "Joe"} , -2458];
var array2 = ["Doe" , 555 , 100];
Array.prototype.push.apply(array1, array2);
/* array1 值為 [12 , "foo" , {name "Joe"} , -2458 , "Doe" , 555 , 100] */
獲取陣列中的最大值和最小值
var numbers = [5, 458 , 120 , -215 ];
var maxInNumbers = Math.max.apply(Math, numbers), //458
maxInNumbers = Math.max.call(Math,5, 458 , 120 , -215); //458
判斷資料型別
Object.prototype.toString.call()
var a = Object.prototype.toString;
console.log(a.call("aaa"));
console.log(a.call(1));
console.log(a.call(true));
console.log(a.call(null));
console.log(a.call(undefined));
console.log(a.call([]));
console.log(a.call(function() {}));
console.log(a.call({}));

參考
- https://www.cnblogs.com/coco1s/p/4833199.html#!comments
- https://zhuanlan.zhihu.com/p/82340026
轉載請註明出處,本文鏈接:https://www.uj5u.com/qianduan/288399.html
標籤:其他
