JS 中的this到底是什么
首先說(shuō)結(jié)論:
fn.call (context,argument[]) ,this 就是你 call 一個(gè)函數(shù)時(shí),傳入的 context。
那大家肯定有疑問(wèn),函數(shù)調(diào)用形式多鐘,如果不是這種調(diào)用形式呢?那又如何確定this呢?
接下來(lái)我們先從函數(shù)調(diào)用形式說(shuō)起
函數(shù)調(diào)用形式
JS(ES5)里面有三種函數(shù)調(diào)用形式:
fn(p1, p2)
obj.child.method(p1, p2)
fn.call(context, p1, p2) //標(biāo)準(zhǔn)調(diào)用形式
其中,第三種調(diào)用形式,才是正常調(diào)用形式函數(shù)調(diào)用標(biāo)準(zhǔn)形式
fn.call(context, p1, p2)
其他兩種都是語(yǔ)法糖,可以等價(jià)地變?yōu)?call 形式:
fn(p1, p2) 等價(jià)于
fn.call(undefined, p1, p2)
obj.child.method(p1, p2) 等價(jià)于
obj.child.method.call(obj.child, p1, p2)
所以,我們知道不論哪種情況的函數(shù)調(diào)用,都可以轉(zhuǎn)換為標(biāo)準(zhǔn)形式:
fn.call(context, p1, p2)
如此,只要是函數(shù)調(diào)用,你就可以輕松的知道this的傳入形式。如果你的函數(shù)調(diào)用形式不是 call 形式,請(qǐng)按照「轉(zhuǎn)換代碼」將其轉(zhuǎn)換為 call 形式。
this 傳入的是什么?
在了解this 就是 call 一個(gè)函數(shù)時(shí),傳入的 context后,我們還需要了解他傳入的是什么
首先我們構(gòu)造一個(gè)監(jiān)聽函數(shù)
$div.on('click',function(){
conlose.log('click')
conlose.log('this')
})
click
<div></div>
在這個(gè)監(jiān)聽函數(shù)中,我們發(fā)現(xiàn),打印出this就是我們監(jiān)聽的元素
那么this是否就是這個(gè)監(jiān)聽元素嗎?實(shí)際不是這樣的
接下來(lái)我們繼續(xù)構(gòu)造一個(gè)事件委托
$div.on('click','button',function(){
conlose.log('click')
conlose.log('this')
})
click
<button></button>
在這個(gè)事件委托中,打印出的this是我們點(diǎn)擊的元素(button),并不是我們監(jiān)聽的元素
那么現(xiàn)在結(jié)論出來(lái)了,this ===e.currentTaget ?
$div.on('click','button',function(e){
conlose.log('click')
if (this === e.currentTaget){
conlose.log('true')
}
})
click
true
實(shí)際證明,的確如此。
通常性看來(lái),this 在JS中是多余的,它只是為了看起來(lái)像Java而設(shè)定的
this的使用方式
在一個(gè)對(duì)象里, 可以用this表示一個(gè)對(duì)象
通常時(shí)候,其實(shí)this是多余的,我們可以直接用對(duì)象名,而不使用this。
但是,某些時(shí)候,我們并不知道對(duì)象名,這時(shí)候就不得不用this來(lái)替代了。
let module = {
element: null,
init: function(){
let $div = this.element //this.element = module.element
//在這里,對(duì)象名module可以用this替代
$div.on('click','button',this.onClickButton)
$div.on('click',function(){
conlose.log('click')
})
},
onClickButton: function(e){
console.log('button is click')
}
}
module.init($div) // 等同于 module.init.call(module,$div)
但是 this在一個(gè)對(duì)象中,是可以改變的
let module = {
element: null,
init: function(){
let $div = this.element
$div.on('click','button',this.onClickButton) //這里的this === module
},
onClickButton: function(e){
console.log('button is click')
console.log('this') //由于觸發(fā)了click監(jiān)聽事件,這里的this已經(jīng)變成了監(jiān)聽事件的點(diǎn)擊元素button
}
}
module.init($div) // 等同于 module.init.call(module,$div)
上例中,由于監(jiān)聽事件的this的值是指向觸發(fā)事件的元素。所以this已經(jīng)改變
可以看出,this在特定場(chǎng)景下,是會(huì)根據(jù)API的源代碼定義所改變。
那么如果我們想指定監(jiān)聽事件傳入的this是我們想要的this,怎么辦?
$div.on('click','button',function(){
module.onClickButton.call(module,e) //這里我們強(qiáng)制指定了傳入this值為module
})
$div.on('click','button',this.onClickButton.bind(this))
我們還可以用bind 來(lái)實(shí)現(xiàn)
$div.on('click','button',this.onClickButton.bind(this))
總結(jié)
- this 就是你 call 一個(gè)函數(shù)時(shí),傳入的 context
- 如果函數(shù)調(diào)用形式不是 call 形式,請(qǐng)將其轉(zhuǎn)換為 call 形式
- 在一個(gè)對(duì)象里, 可以用this表示一個(gè)對(duì)象
- 在監(jiān)聽事件里,this的值是指向觸發(fā)事件的元素
- 任何函數(shù)都可以強(qiáng)制指定傳入的this,也可以使用bind來(lái)改變默認(rèn)傳入this