一個有趣的this指向問題

sako發表於2019-04-12

起源

幾天前在實現一段業務邏輯的時候,寫了一段程式碼,大概就是封裝了一個報告類,然後根據傳入的引數不同,獲取不同的報告。報告類程式碼如下(具體業務邏輯已經去掉,?的程式碼純粹為了說明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!

相關文章