起源
幾天前在實現一段業務邏輯的時候,寫了一段程式碼,大概就是封裝了一個報告類,然後根據傳入的引數不同,獲取不同的報告。報告類程式碼如下(具體業務邏輯已經去掉,?的程式碼純粹為了說明this指向問題而寫)
class ReportServer {
getReport (reportType) {
// 統一的獲取報告方法
return '獲得'+ reportType +'報告'
}
getUserReport () {
// 各自的業務處理。。。
return this.getReport('使用者')
}
getProductReport () {
// 各自的業務處理。。。
return this.getReport('產品')
}
getAreaReport () {
// 各自的業務處理。。。
return this.getReport('地域')
}
}
複製程式碼
呼叫程式碼
const reportType = 'user' // 傳入的引數
const reportServer = new ReportServer()
const reportMap = {
'user': reportServer.getUserReport,
'product': reportServer.getProductReport,
'area': reportServer.getAreaReport
}
reportMap[reportType]()
複製程式碼
然後程式一執行,報了一個 TypeError: this.getReport is not a function 的錯誤。看到錯誤的第一秒,我的腦袋裡閃過了我是誰?我在哪?我在幹什麼?下一秒:不可能!ReportServer這個類裡面明明有getReport這個方法!
思考
言歸正傳,看到這個報錯,第一反應就是this指向不對了,回憶了一下js中關於this的知識:
- 函式有所屬物件,則指向所屬物件
- 函式沒有所屬物件就指向全域性物件
- 用new構造就指向新物件
- 通過 apply 或 call 或 bind 來改變 this 的所指。
沒錯,現在這個情況就是屬於函式有所屬物件,但是這個物件已經不在是reportServer,而是reportMap了,因為js中的this,是在函式真正執行的時候才會確認指向的。看看?的程式碼,更加強力的說明這一點
const reportMap = {
'user': reportServer.getUserReport,
'product': reportServer.getProductReport,
'area': reportServer.getAreaReport,
'test': 'test'
}
class ReportServer {
//...
getUserReport () {
// 各自的業務處理。。。
console.log(this)
return this.getReport('使用者')
}
}
// 最後在執行時,這個this:
{
'user': [Function: getUserReport],
'product': [Function: getProductReport],
'area': [Function: getAreaReport],
'test': 'test'
}
複製程式碼
好吧,記得剛開始學習js的時候,還是有著重的去學習this這方面的知識,然而在實際開發中,還是會不經意的出錯,幸好能第一時間反應過來Orz。
解決
好咯,既然是this指向問題,那麼用call/apply指定正確的this:
reportMap[reportType].call(reportServer) // 輸出:獲得使用者報告
複製程式碼
或者使用?方法
const reportMap = {
'user': 'getUserReport',
'product': 'getProductReport',
'area': 'getAreaReport'
}
reportServer[reportMap[reportType]]() // 輸出:獲得使用者報告
複製程式碼
再或者,改寫為if-else的形式,當然我最開始用hash的寫法,就是不想寫if-else (⊙﹏⊙)
Thanks!