如何修復Vue中的 「this is undefined」 問題

做者:Michael Thiessen
譯者:前端小智
來源:techalyst
點贊再看,養成習慣

本文 GitHub https://github.com/qq44924588... 上已經收錄,更多往期高贊文章的分類,也整理了不少個人文檔,和教程資料。歡迎Star和完善,你們面試能夠參照考點複習,但願咱們一塊兒有點東西。javascript


當咱們使用 Vue 在愉快的開發項目的時候,忽然報了一個錯誤:前端

this is undefined

別擔憂,不僅有你一我的,我也常常遇到這個問題不少次,接下咱們一塊兒來看看如何解決這個問題。vue

一個可能的緣由是混淆了常規函數和箭頭函數的用法,若是你遇到這個問題,我猜你用的是箭頭函數。若是用常規函數替換箭頭函數,它可能會爲你修復這個問題。java

咱們再深刻一點,試着理解爲何會這樣。ios

畢竟,知識就是力量,若是知道形成問題的緣由,那麼咱們未來能夠避免不少挫敗感和時間浪費。git

還有一些其它緣由可能也會出現此類錯誤。github

  • 使用 fetchaxios 獲取數據
  • 使用像 lodashunderscore 這類的庫

理解兩種主要的函數類型

在 JS 中,咱們有兩種不一樣的函數。它們以幾乎相同的方式運做,除了它們處理變量的方式不一樣。面試

這給新舊Javascript開發人員帶來了不少困惑,可是當咱們弄懂這個問題時,就很好會有這個困惑。編程

常規函數

常規函數能夠用幾種不一樣的方式定義。axios

第一種方法在 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,
}

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

匿名函數

當咱們只須要建立一個函數而不須要從其餘任何地方調用它時,匿名函數很是有用。

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

  • 使用 axiosfetch 訪存數據
  • filtermapreduce等函數方法
  • 在 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實例。

讓咱們進一步討論如何使用axiosfetch來獲取數據。

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

若是正在使用fetchaxios獲取異步數據,最好使用 PromisePromise喜歡匿名箭頭函數,它們也使處理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

可是,若是須要將函數傳遞幫助庫,好比lodashunderscore,該怎麼辦呢

與 Lodash 或 Underscore 一塊兒使用

假設咱們的Vue組件上有一個要使用LodashUnderscore方法。如何防止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'
  }
};

將做用域綁定到函數上

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

const boundFunction = unboundFunction.bind(this);

這使咱們在編寫Vue組件時具備更大的靈活性,更輕鬆地重用方法。固然,可讀性相對差點,應該儘可能避免太頻繁地使用它。


代碼部署後可能存在的BUG無法實時知道,過後爲了解決這些BUG,花了大量的時間進行log 調試,這邊順便給你們推薦一個好用的BUG監控工具 Fundebug

原文:
https://www.techalyst.com/pos...


交流

文章每週持續更新,能夠微信搜索「 大遷世界 」第一時間閱讀和催更(比博客早一到兩篇喲),本文 GitHub https://github.com/qq449245884/xiaozhi 已經收錄,整理了不少個人文檔,歡迎Star和完善,你們面試能夠參照考點複習,另外關注公衆號,後臺回覆福利,便可看到福利,你懂的。

相關文章
相關標籤/搜索