call、apply、bind 的用法和區別
首先:call、apply、bind的作用是改變函數運行時的this的指向
var zr = {
a: 1,
fn: function () {
console.log(this.a); //1
}
}
zr.fn();
//相當於zr.fn.call(zr)或者zr.fn.apply(zr);
var zr = {
a: 1,
b: {
a: 2,
fn: function () {
console.log(this.a);
}
}
}
//this指向zr對象中的b,所以打印的是this上一級對象,所以輸出2
zr.b.fn(); //2
//此處使用call或者apply函數 把this從指向b改變爲指向zr
console.log(zr.b.fn.call(zr)) //1
console.log(zr.b.fn.apply(zr)) //1
//也就相當於是變成了
var zr = {
a: 1,
fn: function () {
console.log(this.a); //1
}
}
//由於普通函數(沒有父級對象)沒有任何調用,所以其this就指向window;
function zr() {
var username = "睿睿";
console.log(this.username); //undefined
console.log(this); //Window
}
zr();
//相當於zr.call(undefined)
所以setTimeout作爲一個普通的回調函數,其this是指向window;這就是setTimeout()丟失this的原因;所以在使用setTimeout()的時候:var _this=this;
接下來進入正題
call()可以傳n個參數,但是第一個參數是this將要指向的對象 當第一個參數爲null或者undefined的時候,this默認指向window;之後的參數相當於普通傳參一樣自定義使用;
apply()只可以傳倆個參數,第一個參數和call()的第一個參數一樣,是this將要指向的對象;當第一個參數爲null或者undefined的時候,this默認指向window;;第二個參數是一個數組,相當於把call()除第一個參數外的所有參數放到一個數組中;
var zr = {
a: 1,
b: {
a: 2,
c: {
a: 3,
fn: function (x , y) {
console.log(this.a);
console.log(x+y);
}
}
}
}
//此處使用call或者apply函數 把this從指向c改變爲指向b
zr.b.c.fn.call(zr.b ,1 , 2) //2 3
zr.b.c.fn.apply(zr.b ,[1 , 2] ) //2 3
//此處使用call或者apply函數 把this從指向c改變爲指向zr
zr.b.c.fn.call(zr ,1 , 2) //1 3
zr.b.c.fn.apply(zr ,[1 , 2] ) //1 3
//此處使用call或者apply函數 第一個參數傳null,this默認指向window
zr.b.c.fn.call(null ,1 , 2) //undefined 3
zr.b.c.fn.apply(null ,[1 , 2] ) //undefined 3
其實apply() 和 call() 的用法基本上相同, 唯一的差別就是:當函數需要傳遞>1個變量時, apply() 可以接受一個數組作爲參數, call() 必須接受>1個的單獨變量。
bind()的傳參方式和call()很相似,第一個參數是this將要指向的對象,第一個傳null得話不改變this指向,並且可以在後續的調用中去傳入參數
//後續的調用中去傳入參數
function zr(a, b, c) {
return a * b * c;
}
var fn = zr.bind(null, 2);
//相當於
//function fn(2, b, c) {
//return 2 * b * c;
//}
console.log(fn(3, 4));//24
//相當於
//function fn(2, 3, 4) {
//return 2 * 3 * 4;
//}
//bind()返回的一個改變了 this 之後的新函數;原函數zr中的this並沒有改變;
var obj = {
username:'睿睿'
}
function zr () {
console.log(this.username)
}
var bindfn =zr.bind(obj)
bindfn()//睿睿
//zr () {
//console.log(this.username)
//}