目標:js中this的指向?
問題的引出
- 指出this指向什么
var obj = {
foo: function(){
console.log(this)
}
}
var bar = obj.foo
obj.foo() // 打印出的 this 是 obj
bar() // 打印出的 this 是 window
js中函數(shù)的三種調(diào)用形式
func(p1, p2)
obj.child.method(p1, p2)
func.call(context, p1, p2)
需要記捉朗础: 只有func.call(context, p1, p2)
才是正常的調(diào)用形式仔蝌,其余兩種都是語法糖犁珠,它們最終可以轉(zhuǎn)換為func.call(context灵妨, p1, p2)
這種形式蜓竹。
進行轉(zhuǎn)化
func(p1, p2) ==> func.call(undefined, p1, p2)
obj.child.method(p1, p2) ==> obj.child.method.call(obj, p1, p2)
func.call(context, p1, p2) 無需轉(zhuǎn)換
this,就是上面代碼中的context
注意:
如果傳入的context是null或undefined绑雄,那么window對象就是默認的context(嚴格模式下筝闹,默認context仍然是undeinfed)
實例示例
先看 func(p1, p2) 中的 this 如何確定:
function func(){
console.log(this)
}
func()
轉(zhuǎn)換為:
function func(){
console.log(this)
}
func.call(undefined)
所以航夺,context 就是undefined蕉朵,因此this指向window對象
再看obj.child.method(p1, p2)的this 確定
var obj = {
foo: function(){
console.log(this);
}
}
obj.foo();
轉(zhuǎn)換為
var obj = {
foo: function(){
console.log(this);
}
}
obj.foo.call(obj);
所以this指向的是obj
回到下面代碼
var obj = {
foo: function(){
console.log(this)
}
}
var bar = obj.foo
obj.foo()
bar()
轉(zhuǎn)換
var obj = {
foo: function(){
console.log(this)
}
}
var bar = obj.foo
obj.foo() ==> obj.foo.call(obj) ; // this指向obj
bar() ==> bar.call(undefined); // this指向window
[]語法
function fn (){ console.log(this) }
var arr = [fn, fn2]
arr[0]() // 這里面的 this 又是什么呢?
可以將arr[0]()
轉(zhuǎn)換為arr.0()
(注意:這種語法是錯誤的)阳掐,但形式上與obj.child.method(p1, p2)
就對應(yīng)起來了(arr[0]
是一個對象)始衅;
因此 arr[0]()
==>arr.0()
==> arr.0.call(arr)
,
最終缭保,this指向arr
總結(jié)
- this就是你call一個函數(shù)時汛闸,傳入的cotext
- 如果函數(shù)的調(diào)用形式不是call形式,請按照[轉(zhuǎn)換代碼]將其轉(zhuǎn)換為call形式
第二部分
注意: 要理解了上面的再來看這部分的內(nèi)容
實際工作中面對的this艺骂,可能比上面的情況更晦澀些
Event Handler 中的 this
btn.addEventListener('click', function handler(){
console.log(this) ; // this指向什么
});
記字罾稀:我們說過this是由call/apply來指定的
因此只需要找到handler()被調(diào)用時的代碼就行了
但是addEventListenter是瀏覽器的內(nèi)置函數(shù),我們無法獲
取到代碼钳恕,但是可以文檔 中知道答案别伏,MDN這樣說:
通常來說this的值是觸發(fā)事件的元素的引用蹄衷,這種特性在多個相似的元素使用同一個通用事件監(jiān)聽器時非常讓人滿意。
當使用 addEventListener() 為一個元素注冊事件的時候厘肮,句柄里的 this 值是該元素的引用愧口。其與傳遞給句柄的 event 參數(shù)的 currentTarget 屬性的值一樣。
對于上面說有一點需要注意:“this的值是觸發(fā)事件的元素的引用”轴脐,當使用事件代理時调卑,this指向的并不是目標元素抡砂,但是我們可以通過相關(guān)的方法獲取到觸發(fā)事件的目標元素
可以你可以假想瀏覽器的源碼是這樣寫的
// 當事件被觸發(fā)時
handler.call(event.currentTarget, event)
// 那么 this 是什么不言而喻——就是指向觸發(fā)事件的元素
jQuery Event Handler 中的 this
那么下面代碼中的 this 是什么呢:
$ul.on('click', 'li' , function(){
console.log(this)
})
同樣大咱,不要瞎猜,你要么看 jQuery 源碼是怎么 call 這個函數(shù)的注益,要么看jQuery 文檔碴巾。
jQuery 文檔是這樣寫的:
當調(diào)用jquery的事件處理程序時,this指向當前正在執(zhí)行事件的元素丑搔;對于直接綁定事件而言厦瓢,this代表綁定事件的元素。**對于代理事件而言啤月,this則代表了與selector相匹配的元素
注意煮仇,如果事件是從后代元素冒泡上來的話,那么 this 就有可能不等于 event.target谎仲。)若要使用 jQuery 的相關(guān)方法浙垫,可以根據(jù)當前元素創(chuàng)建一個 jQuery 對象,即使用 $(this)郑诺。
總結(jié)一下如何確定 this 是值
- 看源碼中對應(yīng)函數(shù)是怎么被call的(最靠譜的方法)
- 看文檔
- console.log(this)
如何強制指定 this 的值夹姥?
自己寫 call / apply 即可:
function handlerWrapper(event){
function handler(){
console.log(this) // 請問這里的 this 是什么
}
handler.call({name:'饑人谷'}, event)
}
btn.addEventListener('click', handlerWrapper)
你也可以直接使用 bind,與上面的代碼效果差不多:
function handler(){
console.log(this) // 請問這里的 this 是什么
}
var handlerWrapper = handler.bind({name:'饑人谷'})
btn.addEventListener('click', handlerWrapper)
上面三句代碼可以擠成一句:
btn.addEventListener('click', function(){
console.log(this) // 請問這里的 this 是什么
}.bind({name:'饑人谷'}))
這是前端里一個常見的套路辙诞。
this 不難辙售,就看你有沒有按照 call / apply 來理解函數(shù)了。