如何修復Vue中的 “this is undefined” 問題


當我們使用 vue 在愉快的開發項目的時候,突然報了一個錯誤:

this is undefined 

別擔心,不只有你一個人,我也經常遇到這個問題很多次,接下我們一起來看看如何解決這個問題。

一個可能的原因是混淆了常規函數和箭頭函數的用法,如果你遇到這個問題,我猜你用的是箭頭函數。如果用常規函數替換箭頭函數,它可能會為你修復這個問題。

我們再深入一點,試着理解為什么會這樣。

畢竟,知識就是力量,如果知道造成問題的原因,那么我們將來可以避免很多挫敗感和時間浪費。

還有一些其它原因可能也會出現此類錯誤。

  • 使用 fetch 或 axios 獲取數據
  • 使用像 lodash 或 underscore 這類的庫

 

理解兩種主要的函數類型

在 js 中,我們有兩種不同的函數。它們以幾乎相同的方式運作,除了它們處理變量的方式不同。

這給新舊JavaScript開發人員帶來了很多困惑,但是當我們弄懂這個問題時,就很好會有這個困惑。

 

常規函數

常規函數可以用幾種不同的方式定義。

第一種方法在 vue 組件中較不常見,因為寫出來要更長一些:

methods: { regularFunction: function() { // Do some stuff } } 

第二種方法是簡寫方式,我們也經常使用:

methods: {
  shorthandFunction() {
    // Do some stuff } } 

在像這樣的常規函數中,this將引用函數的“所有者”。因為我們是在Vue組件上定義它的,所以this指的是Vue組件。

在大多數情況下,我們應該在 Vue 中使用常規函數,特別是在創建時

  • methods
  • computed props
  • watched props

雖然常規函數通常是我們所需要的,但是箭頭函數也非常方便。

 

箭頭函數

箭頭函數可以更短,更快的編寫,因此最近獲得了廣泛的歡迎。但是,它們在對象上定義方法時並沒有太大的不同,就像我們在編寫Vue組件時所做的那樣。

這是他們在Vue組件上的樣子:

methods: { arrowFunction: () => { // Do some stuff } } 

在處理 this 問題時,真正的差異開始發揮作用。

箭頭函數采用詞法作用域,意味着箭頭函數從它的上下文中獲取this。

如果試圖從Vue組件上的箭頭函數內部訪問 this,將得到一個錯誤,因為 this 不存在

data() {
  return { text: 'This is a message', }; }, methods: { arrowFunction: () => { console.log(this.text); // ERROR! this is undefined } } 

簡而言之,盡量避免在Vue組件上使用箭頭函數。這將會省去許多頭痛和困惑的問題。

有時使用箭頭函數是很好的,但這只在不引用this的情況下才有效。

computed: { location: () => window.location, } 

現在我們知道兩種主要的函數類型,如何正確使用它們?

 

匿名函數

當我們只需要創建一個函數而不需要從其他任何地方調用它時,匿名函數非常有用。

下面是使用匿名函數的一些場景

  • 使用 axios 或 fetch 訪存數據
  • filter、map和reduce等函數方法
  • 在 Vue 方法中的任何地方

來個例子看一下:

// Fetching data fetch('/getSomeData').then((data) => { this.data = data; }); // Functional methods const array = [1, 2, 3, 4, 5]; const filtered = array.filter(number => number > 3); const mapped = array.map(number => number * 2); const reduced = array.reduce((prev, next) => prev + next); 

從示例中可以看到,大多數情況下,當我們創建匿名函數時,使用箭頭函數。我們通常使用箭頭函數有幾個原因

  • 更短、更簡潔的語法
  • 改善可讀性
  • this 取自父類

在Vue方法中,箭頭函數也可以作為匿名函數使用。

等等,我們不是剛發現當我們試圖訪問 this 時,箭頭函數不起作用嗎?

這就是區別所在。

當我們在常規函數或簡寫函數中使用箭頭函數時,常規函數將this設置為我們的Vue組件,而箭頭函數則不一樣。

來個例子:

data() {
  return { match: 'This is a message', }; }, computed: { filteredMessages(messages) { console.log(this); // Vue const filteredMessages = messages.filter( // 引用我們的Vue組件 (message) => message.includes(this.match) ); return filteredMessages; } } 

filter方法可以訪問this.match,因為箭頭函數使用的方法與filteredMessages方法使用的上下文相同。 由於此方法是常規函數(而不是箭頭函數),因此將其自身的上下文設置為Vue實例。

讓我們進一步討論如何使用axios或fetch來獲取數據。

 

在獲取數據時使用正確的函數

如果正在使用fetch或axios獲取異步數據,最好使用 Promise。Promise喜歡匿名箭頭函數,它們也使處理this問題變得容易得多。

如果你正在獲取一些數據並想在你的組件上設置它,這是你應該做的正確的方式:

export default { data() { return { dataFromServer: undefined, }; }, methods: { fetchData() { fetch('/dataEndpoint') .then(data => { this.dataFromServer = data; }) .catch(err => console.error(err)); } } }; 

請注意,我們如何在 Vue 組件上使用常規函數作為方法,然后在 Promise 內部使用匿名箭頭函數

.then(data => { this.dataFromServer = data; }) 

在fetchData()作用域內,我們將this設置為Vue組件,因為它是一個常規函數。由於箭頭函數使用外部作用域作為它們自己的作用域,因此箭頭函數也將this設置為我們的Vue組件。

這允許我們通過this訪問 Vue 組件並更新dataFromServer。

但是,如果需要將函數傳遞幫助庫,比如lodash或underscore,該怎么辦呢

 

與 Lodash 或 Underscore 一起使用

假設我們的Vue組件上有一個要使用Lodash或Underscore方法。如何防止this is undefine的錯誤。

如果你用過 react ,你可能見過類似的東西。

這是我們用Vue做的。

created() {
  this.methodToDebounce = _.debounce(this.methodToDebounce, 500); }, methods: { methodToDebounce() { // Do some things here } } 

就是這樣!

我們要做的就是獲取函數,將其包裝在debounce函數中,然后返回一個內建了debounce的新函數。現在,當我們在Vue組件上調用this.methodToDebounce()時,我們將調用debounced版本。

 

什么是詞法作用域

如前所述,常規函數和箭頭函數之間存在差異的主要原因與詞法作用域有關。來分析一下它的含義。

首先,作用域是程序中存在變量的任何區域。在JavaScript中,window 變量具有全局作用域,它在任何地方都可用。盡管大多數變量被限制在定義它們的函數、它們所屬的類或模塊中。

其次,單詞“詞法”僅僅意味着作用域由你如何編寫代碼決定。某些編程語言只在程序運行時才確定作用域內的內容。這可能會讓人很困惑,所以大多數語言都只使用詞法作用域。

箭頭函數使用詞法作用域,而常規函數和簡寫函數不使用。

這里最棘手的部分是詞法作用域如何在函數中影響 this。對於箭頭函數,this與外部作用域的this綁定在一起。常規函數的this綁定方式有些奇怪,這就是引入箭頭函數的原因,也是為什么大多數人盡可能多地使用箭頭函數的原因。

 

作用域如何在函數中工作

下面是一些示例,它們演示了作用域如何在這兩種函數類型之間以不同的方式工作

// 此變量在 window 作用域內 window.value = 'Bound to the window'; const object = { // 此變量在 object 作用域內 value: 'Bound to the object', arrowFunction: () => { console.log(this.value); // 'Bound to the window' }, regularFunction() { console.log(this.value); // 'Bound to the object' } };

資源搜索網站大全https://55wd.com 廣州品牌設計公司http://www.maiqicn.com

將作用域綁定到函數上

我們可以使用 bind 方法來改變 this 的綁定

const boundFunction = unboundFunction.bind(this); 

這使我們在編寫Vue組件時具有更大的靈活性,更輕松地重用方法。當然,可讀性相對差點,應該盡量避免太頻繁地使用它。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM