一些誤解
- 指向自身阅爽?(并不是所有時(shí)候都指向自身)
- 作用域問(wèn)題?(this并不一定指向函數(shù)的作用域巷帝,并且在任何時(shí)候都不指向函數(shù)的詞法作用域)
- this到底是什么?(this是運(yùn)行時(shí)綁定的并不是在編寫(xiě)時(shí)綁定扭吁,他的上下文取決于函數(shù)調(diào)用時(shí)的各種條件和函數(shù)聲明的位置沒(méi)有任何關(guān)系炫掐,只取決于函數(shù)的調(diào)用方式)
this的指向
- 全局范圍使用this和全局函數(shù)調(diào)用都指向全局對(duì)象(在嚴(yán)格模式下undefined)
- 方法調(diào)用內(nèi)this指向調(diào)用對(duì)象
- new綁定調(diào)用構(gòu)造函數(shù),在函數(shù)內(nèi)部指向新創(chuàng)建的對(duì)象
- 通過(guò)call子库、apply顯式的的設(shè)置this對(duì)象舱权,指向設(shè)置的對(duì)象
關(guān)于call、apply仑嗅、bind
var links = document.querySelectorAll('nav li');
for (var i = 0; i < links.length; i++) {
console.log(this); // [object Window]}
有時(shí)候我們需要根據(jù)實(shí)際的需求來(lái)變化代碼的作用域宴倍,就需要
call、apply仓技、bind動(dòng)態(tài)的傳入函數(shù)引用鸵贬。
var links = document.querySelectorAll('nav li');
for (var i = 0; i < links.length; i++) {
(function () {
console.log(this);
}).call(links[i]);
}
其中.call(scope, arg1, arg2, arg3)輸入單個(gè)參數(shù),而.apply(scope, [arg1, arg2])輸入數(shù)組作為參數(shù)脖捻。在ES5中引入了bind方法阔逼,bind()并不觸發(fā)函數(shù),它僅僅是在函數(shù)觸發(fā)前綁定值地沮。
nav.addEventListener('click', toggleNav.bind(scope, arg1, arg2), false);
在不需要調(diào)用的時(shí)候就可以傳遞參數(shù)嗜浮,函數(shù)并沒(méi)被觸發(fā)涯保,scope可以被改變,且參數(shù)在等著傳遞周伦。
其它
bind源碼
if(!('bind' in Function.prototype)){
Function.prototype.bind = function(){
var fn = this,
context = arguments[0],
args = Array.prototype.slice.call(arguments, 1);
return function(){
return fn.apply(context, args.concat(arguments));
}
}
}
bind()方法通常被用在上下文丟失的場(chǎng)景下,例如面向?qū)ο蠛褪录幚砦椿摹V砸@么做专挪,是因?yàn)楣?jié)點(diǎn)的addEventListener方法總是為事件處理器所綁定的節(jié)點(diǎn)的上下文中執(zhí)行回調(diào)函數(shù),這就是它應(yīng)該表現(xiàn)的那樣片排。但是寨腔,如果你想要使用高級(jí)的面向?qū)ο蠹夹g(shù),或需要你的回調(diào)函數(shù)成為某個(gè)方法的實(shí)例率寡,你將需要手動(dòng)調(diào)整上下文迫卢。這就是bind方法所帶來(lái)的便利之處。
bind源碼中調(diào)用了Array的slice方法冶共,我們知道arguments對(duì)象并不是一個(gè)真正的數(shù)組乾蛤,而是一個(gè)類(lèi)數(shù)組對(duì)象,雖然具有l(wèi)ength屬性捅僵,并且值也能夠被索引家卖,但是它們不支持原生的數(shù)組方法,例如slice和push庙楚。但是上荡,由于它們具有和數(shù)組類(lèi)似的行為,數(shù)組的方法能夠被調(diào)用和劫持馒闷,因此我們可以通過(guò)類(lèi)似于上面代碼的方式達(dá)到這個(gè)目的酪捡,其核心是利用call方法。