call,apply,bind
在JavaScript中,call
、apply
和bind
是Function
對象自帶的三個方法,都是為了改變函數體內部 this
的指向。
apply 、 call 、bind
三者第一個參數都是 this
要指向的對象,也就是想指定的上下文;
apply 、 call 、bind
三者都可以利用后續參數傳參;
bind 是返回對應 函數,便於稍后調用;apply 、call
則是立即調用 。
——————————————————————————————————————————————————————————————————————————-
例子:
1.
function fruits() {} fruits.prototype = { color: 'red', say: function() { console.log('My color is' + this.color); } } var apple = new fruits; apple.say(); // 此時方法里面的this 指的是fruits // 結果: My color is red
但是如果我們有一個對象 banana= {color : 'yellow'}
,我們不想重新定義 say 方法,那么我們可以通過 call 或 apply 用 apple 的 say 方法:
banana = { color: 'yellow' } apple.say.call(banana); //此時的this的指向已經同過call()方法改變了,指向的是banana,this.color就是banana.color='yellow'; //結果是My color is yellow apple.say.apply(banana);//同理,此時的this的指向已經同過apply()方法改變了,指向的是banana,this.color就是banana.color ='yellow'; //My color is yellow // 如果傳入的是 null: apple.say.apply(null); // null是window下的,此時,this 就指向了window ,但是window下並沒有clolr這個屬性,因此this.clolr就是window.color=undefined; //My color is undefined
2.對於 apply、call 二者而言,作用完全一樣,只是接受 參數 的方式不太一樣。call 是把參數按順序傳遞進去,而 apply 則是把參數放在數組 里。
var array1 = [12,'foo',{name:'Joe'},-2458]; var array2 = ['Doe' , 555 , 100]; Array.prototype.push.call(array1, array2); // 這里用 call 第二個參數不會把 array2 當成一個數組,而是一個元素 //等價於array1.push(‘‘'Doe' , 555 , 100’’); //array1.length=5; Array.prototype.push.apply(array1, array2); // 這里用 apply 第二個參數是一個數組 // 等價於: array1.push('Doe' , 555 , 100); //array1.length=7;
3.類(偽)數組使用數組方法
var divElements = document.getElementsByTagName('div'); //雖然 divElements 有length屬性,但是他是一個偽數組,不能使用數組里面的方法 Array.isArray(divElements);// false var domNodes = Array.prototype.slice.call(document.getElementsByTagName('div')); // 將數組對象Array里的this指向偽數組document.getElementsByTagName('div'),
//slice() 方法可從已有的數組中返回選定的元素,不傳參數是,返回整個數組
Array.isArray(domNodes);// true
4. 驗證一個對象的類型可以用:
Object.prototype.toString.call(obj)
5.bind()
方法,MDN 的解釋是:bind()
方法會創建一個 新函數,稱為綁定函數,當調用這個綁定函數時,
綁定函數會以創建它時傳入 bind()
方法的第一個參數 作為 this
,傳入 bind()
方法的 第二個以及以后的參
數加上綁定函數運行時本身的參數按照順序作為原函數的參數來調用原函數。
var bar = function(){ console.log(this.x); } var foo = { x:3 } bar(); // undefined var func = bar.bind(foo); //此時this已經指向了foo,但是用bind()方法並不會立即執行,而是創建一個新函數,如果要直接調用的話 可以 bar.bind(foo)()
func(); // 3
6.在 Javascript 中,多次 bind()
是無效的。更深層次的原因, bind()
的實現,相當於使用函數在內部包了一個 call / apply
,第二次 bind()
相當於再包住第一次 bind()
,故第二次以后的 bind
是無法生效的。
var bar = function(){ console.log(this.x); } var foo = { x:3 } var sed = { x:4 } var func = bar.bind(foo).bind(sed); func(); //3 var fiv = { x:5 } var func = bar.bind(foo).bind(sed).bind(fiv); func(); //3
7.apply、call、bind
三者相比較,之間又有什么異同呢?何時使用 apply、call
,何時使用 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
參考:
- 深入淺出 妙用Javascript中apply、call、bind
- Function.prototype.bind()
- Function.prototype.call()
- Function.prototype.apply()