為什么需要這些瘪贱?主要是因?yàn)閠his纱控,來看看this干的好事。
box.onclick = function(){
function fn(){
alert(this);
}
fn();
};
我們原本以為這里面的this指向的是box,然而卻是Window菜秦。一般我們這樣解決:
box.onclick = function(){
var _this = this;
function fn(){
alert(_this);
}
fn();
};
將this保存下來甜害。
還有一些情況,有時(shí)我們想讓偽數(shù)組也能夠調(diào)用數(shù)組的一些方法球昨,這時(shí)call尔店、apply、bind就派上用場了主慰。
我們先來解決第一個(gè)問題修復(fù)this指向嚣州。
box.onclick = function(){
function fn(){
alert(this);
}
fn();
};
改成如下:
box.onclick = function(){
function fn(){
console.log(this);
}
fn.call(this);
};
很神奇吧,call的作用就是改變this的指向的共螺,第一個(gè)傳的是一個(gè)對象该肴,就是你要借用的那個(gè)對象。
fn.call(this);
這里的意思是讓this去調(diào)用fn這個(gè)函數(shù)藐不,這里的this是box匀哄,這個(gè)沒有意見吧秦效?如果這個(gè)你不清楚,很可能你是javscript的新朋友涎嚼。box調(diào)用fn阱州,這句話非常重要,我們知道this它始終指向一個(gè)對象法梯,剛好box就是一個(gè)對象苔货。那么fn里面的this就是box。
box.onclick = function(){
function fn(){
console.log(this);
}
fn.call(this);
};
這句話在某些情況下是可以簡寫的立哑,比如:
box.onclick = function(){
var fn = function(){
console.log(this); //box
}.call(this);
};
或者這樣:
box.onclick = function(){
(function(){
console.log(this);
}.call(this)); //box
};
又或者這樣:
var objName = {name:'JS2016'};
var obj = {
name:'0 _ 0',
sayHello:function(){
console.log(this.name);
}.bind(objName)
};
obj.sayHello();//JS2016
call和apply夜惭、bind但是用來改變this的指向的,但也有一些小小的差別铛绰。下面我們來看看它們的差別在哪滥嘴。
function fn(a,b,c,d){
console.log(a,b,c,d);
}
//call
fn.call(null,1,2,3);
//apply
fn.apply(null,[1,2,3]);
//bind
var f = fn.bind(null,1,2,3);
f(4);
結(jié)果如下:
1 2 3 undefined
1 2 3 undefined
1 2 3 4
前面說過第一個(gè)參數(shù)傳的是一個(gè)你要借用的對象,但這么我們不需要至耻,所有就傳了一個(gè)null若皱,當(dāng)然你也可以傳其他的,反正在這里沒有用到尘颓,除了第一個(gè)參數(shù)后面的參數(shù)將作為實(shí)際參數(shù)傳入到函數(shù)中走触。
call就是挨個(gè)傳值,apply傳一個(gè)數(shù)組疤苹,bind也是挨個(gè)傳值互广,但和call和apply還有多少不同,使用call和apply會(huì)直接執(zhí)行這個(gè)函數(shù)卧土,而bind并不會(huì)而是將綁定好的this重新返回一個(gè)新函數(shù)惫皱,什么時(shí)候調(diào)用由你自己決定。
var objName = {name:'JS2016'};
var obj = {
name:'0 _ 0',
sayHello:function(){
console.log(this.name);
}.bind(objName)
};
obj.sayHello();//JS2016
這里也就是為什么我要用bind的原因尤莺,如果用call的話就會(huì)報(bào)錯(cuò)了旅敷。自己想想這個(gè)sayHello在obj都已經(jīng)執(zhí)行完了,就根本沒有sayHello這個(gè)函數(shù)了颤霎。
這幾個(gè)方法使用的好的話可以幫你解決不少問題比如:
正常情況下Math.max只能這樣用
Math.max(10,6)
但如果你想傳一個(gè)數(shù)組的話你可以用apply
var arr = [1,2,30,4,5];
console.log(Math.max.apply(null,arr));
又或者你想讓偽數(shù)組調(diào)用數(shù)組的方法
function fn(){
[].push.call(arguments,3);
console.log(arguments); //[1, 2, 3]
}
fn(1,2);
再者:
var arr = ['aaabc'];
console.log(''.indexOf.call(arr,'b')); //3
牛逼不媳谁,簡直偷梁換柱,當(dāng)然還有很多可以利用的友酱,自己盡情花輝去吧晴音。
簡單說一下這種偷梁換柱的原理吧,實(shí)際上瀏覽器內(nèi)部根本就不在乎你是誰缔杉,它只關(guān)心你傳給我的是不是我能夠運(yùn)行的锤躁,如下:
正常情況
var str = 'aaabc';
console.log(str.indexOf('b'));
而這種情況其實(shí)做的事情和上面一模一樣,看我來拆解或详。
var arr = ['aaabc'];
''.indexOf.call(arr);
這句話就是說讓arr調(diào)用字符串的indexOf方法系羞,前面說過了瀏覽器內(nèi)部不在乎你是誰加缘,所以誰都可以來調(diào)用,但不是100%成功觉啊,具體看如下。
''.indexOf.call(arr,'b')
這里的arr就是['aaabc']沈贝,內(nèi)部很可能拆成了'aaabc'杠人,因此就成了下面的這段代碼。
'aaabc'.indexOf('b');
這就是它們的秘密宋下。
這里得說一下bind在某些瀏覽器下不兼容嗡善。我們來模擬一個(gè)玩玩。
Function.prototype.$bind = function(obj){
//保存當(dāng)前this
var _this = this;
//截取除了第一個(gè)以外的所有實(shí)際參數(shù)
var a = [].slice.call(arguments,1);
//返回一個(gè)新函數(shù)
return function(){
//讓當(dāng)前那個(gè)調(diào)用的函數(shù)的this指向obj学歧,并且把實(shí)參傳給它罩引,這里用了concat是因?yàn)椋覀兛赡茉诮壎ㄒ院筮€傳遞參數(shù)枝笨,所以才把他們合并起來袁铐。如f(4)這個(gè)是在綁定以后傳的參數(shù),a這個(gè)argument是綁定時(shí)的横浑。
_this.apply(obj,a.concat([].slice.call(arguments)));
};
};
function fn(a,b,c,d){
console.log(a,b,c,d);
}
var f = fn.$bind(null,1,2,3);
f(4);
這個(gè)方法和實(shí)際上的bind還是差別很大的剔桨,如
var arr = ['JSS'];
var index = ''.indexOf.$bind(arr,'S');
console.log(index())
function fff(){
[].push.$bind(arguments,1);
console.log(arguments);
}
fff();