做者:Michael Thiessen
譯者:前端小智
來源:techalyst
點贊再看,養成習慣本文
GitHub
https://github.com/qq44924588... 上已經收錄,更多往期高贊文章的分類,也整理了不少個人文檔,和教程資料。歡迎Star和完善,你們面試能夠參照考點複習,但願咱們一塊兒有點東西。javascript
當咱們使用 Vue 在愉快的開發項目的時候,忽然報了一個錯誤:前端
this is undefined
別擔憂,不僅有你一我的,我也常常遇到這個問題不少次,接下咱們一塊兒來看看如何解決這個問題。vue
一個可能的緣由是混淆了常規函數和箭頭函數的用法,若是你遇到這個問題,我猜你用的是箭頭函數。若是用常規函數替換箭頭函數,它可能會爲你修復這個問題。java
咱們再深刻一點,試着理解爲何會這樣。ios
畢竟,知識就是力量,若是知道形成問題的緣由,那麼咱們未來能夠避免不少挫敗感和時間浪費。git
還有一些其它緣由可能也會出現此類錯誤。github
fetch
或 axios
獲取數據lodash
或 underscore
這類的庫在 JS 中,咱們有兩種不一樣的函數。它們以幾乎相同的方式運做,除了它們處理變量的方式不一樣。面試
這給新舊Javascript開發人員帶來了不少困惑,可是當咱們弄懂這個問題時,就很好會有這個困惑。編程
常規函數能夠用幾種不一樣的方式定義。axios
第一種方法在 Vue 組件中較不常見,由於寫出來要更長一些:
methods: { regularFunction: function() { // Do some stuff } }
第二種方法是簡寫方式,咱們也常用:
methods: { shorthandFunction() { // Do some stuff } }
在像這樣的常規函數中,this
將引用函數的「全部者」。由於咱們是在Vue組件上定義它的,因此this
指的是Vue組件。
在大多數狀況下,咱們應該在 Vue 中使用常規函數,特別是在建立時
雖然常規函數一般是咱們所須要的,可是箭頭函數也很是方便。
箭頭函數能夠更短,更快的編寫,所以最近得到了普遍的歡迎。可是,它們在對象上定義方法時並無太大的不一樣,就像咱們在編寫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
等函數方法來個例子看一下:
// 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);
從示例中能夠看到,大多數狀況下,當咱們建立匿名函數時,使用箭頭函數。咱們一般使用箭頭函數有幾個緣由
在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
,該怎麼辦呢
假設咱們的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' } };
咱們可使用 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和完善,你們面試能夠參照考點複習,另外關注公衆號,後臺回覆福利,便可看到福利,你懂的。