前言:
總能看到很多的面試題中都包含有對call、apply和bind的理解,也一直是一個毒瘤。今天突然開竅了,就寫個博客記錄一下
先拋出一個問題:
爲什麼會出現call、apply和bind?
答:他們就是用來解決this指向的,即就是可以連接上下文
先來舉個栗子:
function show() {}
show.prototype = {
a = 'fish',
eat = function() {
console.log('I like eat' + this.a)
}
}
var wang = new show
wang.eat() //'I like eat fish'
但是我不光愛喫魚還愛喫蘋果。但是又不想重新寫一個新的eat方法怎麼辦?
就可以通過這個 神奇的東西來搞
banana = {
a: "apple"
}
wang.eat.call(banana); //I like eat apple
wang.eat.apply(banana); //I like eat apple
所以,可以看出 call 和 apply 是爲了動態改變 this 而出現的,當一個 object 沒有某個方法但是其他的有,我們可以藉助call或apply用其它對象的方法來操作。
apply、call 的區別
其實這兩個的作用是完全一樣的,都可以改變this的指向,第一個參數都是要指向的對象,也就是要指定的上下文,第二個參數就不一樣了。
call傳入的參數是一個接一個的參數,而apply可以用一個數組包起來,或者用一個僞數組arguments
所以說,當參數固定的時候可以用call傳入,當參數不固定的時候就要用apply
**** 補充說明:****
將一個僞數組轉換爲真正的數組
var arrayLike = {
0: 'zhangsan',
1: 'lisi',
2: 'wangwu',
length: 3
}
var arrayList = Array.prototype.slice.call(arrayLike)
console.log(arrayList) // ['zhangsan','lisi','wangwu']
關於bind
MDN的解釋是:bind()方法會創建一個新函數,稱爲綁定函數,當調用這個綁定函數時,綁定函數會以創建它時傳入 bind()方法的第一個參數作爲 this,傳入 bind() 方法的第二個以及以後的參數加上綁定函數運行時本身的參數按照順序作爲原函數的參數來調用原函數。
var bar = function(){
console.log(this.x);
}
var foo = {
x:3
}
bar(); // undefined
var func = bar.bind(foo);
func(); // 3
還有一點就是連續調用多個bind不會疊加,執行的永遠都是第一個bind。
原因是,在Javascript中,多次 bind() 是無效的。更深層次的原因, bind() 的實現,相當於使用函數在內部包了一個 call / apply ,第二次 bind() 相當於再包住第一次 bind() ,故第二次以後的 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
仔細觀察會發現bind的方法後面還有一對括號,也就是說bind方法不會立即執行,而是會有一個回調
所以說當有些不需要立即執行的就可以用bind
再總結一下:
- apply 、 call 、bind 三者都是用來改變函數的this對象的指向的;
- apply 、 call 、bind 三者第一個參數都是this要指向的對象,也就是想指定的上下文;
- apply 、 call 、bind 三者都可以利用後續參數傳參;
- bind 是返回對應函數,便於稍後調用;apply 、call 則是立即調用 。