call、apply、bind這三個方法,用來切換/固定this的指向。
1 .call() 方法
函數(shù)實(shí)例的call方法,可以指定函數(shù)內(nèi)部this的指向(即函數(shù)執(zhí)行時(shí)所在的作用域),然后在所指定的作用域中,調(diào)用該函數(shù)。
var obj = {};
var f = function () {
return this;
};
f() === window // true
f.call(obj) === obj // true
上面代碼中,全局環(huán)境運(yùn)行函數(shù)f時(shí),this指向全局環(huán)境(瀏覽器為window對象);call方法可以改變this的指向,指定this指向?qū)ο髈bj,然后在對象obj的作用域中運(yùn)行函數(shù)f。
call方法的參數(shù),應(yīng)該是一個對象。如果參數(shù)為空、null和undefined,則默認(rèn)傳入全局對象。
var n = 123;
var obj = { n: 456 };
function a() {
console.log(this.n);
}
a.call() // 123
a.call(null) // 123
a.call(undefined) // 123
a.call(window) // 123
a.call(obj) // 456
上面代碼中,a函數(shù)中的this關(guān)鍵字,如果指向全局對象,返回結(jié)果為123。如果使用call方法將this關(guān)鍵字指向obj對象,返回結(jié)果為456??梢钥吹剑绻鹀all方法沒有參數(shù),或者參數(shù)為null或undefined,則等同于指向全局對象。
2.apply()方法
apply方法的作用與call方法類似,也是改變this指向,然后再調(diào)用該函數(shù)。唯一的區(qū)別就是,它接收一個數(shù)組作為函數(shù)執(zhí)行時(shí)的參數(shù),使用格式如下。
func.apply(thisValue, [arg1, arg2, ...])
apply方法的第一個參數(shù)也是this所要指向的那個對象,如果設(shè)為null或undefined,則等同于指定全局對象。第二個參數(shù)則是一個數(shù)組,該數(shù)組的所有成員依次作為參數(shù),傳入原函數(shù)。原函數(shù)的參數(shù),在call方法中必須一個個添加,但是在apply方法中,必須以數(shù)組形式添加。
function f(x, y){
console.log(x + y);
}
f.call(null, 1, 1) // 2
f.apply(null, [1, 1]) // 2
上面代碼中,f函數(shù)本來接受兩個參數(shù),使用apply方法以后,就變成可以接受一個數(shù)組作為參數(shù)。
3.bind()方法
bind方法用于將函數(shù)體內(nèi)的this綁定到某個對象,然后返回一個新函數(shù)。
bind方法的參數(shù)就是所要綁定this的對象
舉例:
var counter = {
count: 0,
inc: function () {
this.count++;
}
};
var func = counter.inc.bind(counter);
func();
counter.count // 1
上面代碼中,counter.inc方法被賦值給變量func。這時(shí)必須用bind方法將inc內(nèi)部的this,綁定到counter,否則就會出錯。
this綁定到其他對象也是可以的。
var counter = {
count: 0,
inc: function () {
this.count++;
}
};
var obj = {
count: 100
};
var func = counter.inc.bind(obj);
func();
obj.count // 101
上面代碼中,bind方法將inc方法內(nèi)部的this,綁定到obj對象。結(jié)果調(diào)用func函數(shù)以后,遞增的就是obj內(nèi)部的count屬性。
bind還可以接受更多的參數(shù),將這些參數(shù)綁定原函數(shù)的參數(shù)。
var add = function (x, y) {
return x * this.m + y * this.n;
}
var obj = {
m: 2,
n: 2
};
var newAdd = add.bind(obj, 5);
newAdd(5) // 20
上面代碼中,bind方法除了綁定this對象,還將add函數(shù)的第一個參數(shù)x綁定成5,然后返回一個新函數(shù)newAdd,這個函數(shù)只要再接受一個參數(shù)y就能運(yùn)行了。
如果bind方法的第一個參數(shù)是null或undefined,等于將this綁定到全局對象,函數(shù)運(yùn)行時(shí)this指向頂層對象(瀏覽器為window)。
function add(x, y) {
return x + y;
}
var plus5 = add.bind(null, 5);
plus5(10) // 15
上面代碼中,函數(shù)add內(nèi)部并沒有this,使用bind方法的主要目的是綁定參數(shù)x,以后每次運(yùn)行新函數(shù)plus5,就只需要提供另一個參數(shù)y就夠了。而且因?yàn)閍dd內(nèi)部沒有this,所以bind的第一個參數(shù)是null,不過這里如果是其他對象,也沒有影響。