vue中methods中的方法閉包緩存問題


vue中methods中的方法閉包緩存問題

問題背景

需求描述

  • 在路由的導航欄中需要, 判斷是否為第一次點擊
  • 需要一個標志位來記錄是否點擊過
  • 現狀:
    • 這個標志位只在一個函數中用過.不希望存放全局
    • 希望在這個methods中形成閉包, 用來緩存這個函數
    • 做出如下嘗試后, 發現可以實現.
  • 當前問題:
    • 不能在閉包調用時找到正確的this.

詭異點

  • 測試使用時: 返回的this找到了window
// 測試使用:
  <div id="app">
    <button @click="test">測試按鈕</button>
  </div>
  <script>
    var app = new Vue({
      el: '#app',
      methods: {
        test: (() => {
          `use strict`
          console.log(this) // Window
          var flag = true
          return () => {
            console.log(this) // Window
            flag = false
          }
        })()
      }
    })
  </script>
  • 實際項目中的this變成了undefined錯誤截圖

  • 更加詭異的是debugger之后, 我們一步步來看

  • 當前代碼:

    pointJump: (() => {
      let isFirstChanged = false;
      console.log(this);
      debugger;
      return entry => {
        console.log(this);
        console.log(isFirstChanged);
        debugger;
        isFirstChanged = true;
      };
    })(),
  • 操作:
    1. 刷新頁面, 第一次函數立即執行第一步
    2. 頁面生成完成后: 我們再次通過按鈕觸發事件: 此時debugger顯示內存中為Vue的頂級對象, 而在控制台打印出來的依舊是undefined
      在debugger中顯示的內容
      控制台顯示的內容

執行過程分析

  • 第一次執行的時候為undefined是正常的, 因為第一次閉包執行, 沒有找到this
  • 當我們再次執行的時候, 雖然調用起來的上下文, 也就是this已經改了, 但是因為在作用域中那個this所代表的空間還是undefined, 所以沒有能改變過來.
  • 就造成了我們所看到的詭異的現象.

與測試文件有差別的原因

  • 因為在測試環境下, 沒有能開啟嚴格模式.
  • 經過兩次不同位置的的開啟嘗試, 都不對
  • 依舊可以找到window對象
  • 現在推測是在vue內部進行的實現, 因為引入的vue版本不同.需要再進行測試, 看來源碼還是要好好過一遍
  <script>
    var app = new Vue({
      el: '#app',
      methods: {
        test: (() => {
          `use strict`
          console.log(this) // Window
          var flag = true
          return () => {
            console.log(this) // Window
            flag = false
          }
        })()
      }
    })
  </script>

最后找到原因的測試

  • 因為箭頭函數的this是不會改變, 擁有根據父級能夠返回的this
  • 然后因為上面的閉包環境中的this, 指向的一直都是undefined
const test = (() => {
  let aaa = true;
  return function () {
    console.log(this);
    aaa = false;
  };
})();
mainJump(entry) {
  test.call(this);
},

解決方法

  • 形成閉包返回的函數中, 不要使用箭頭函數, 使用function定義即可
    pointJump: (() => {
      let isFirstChanged = false;
      return function () {
        console.log(this); // Vue的頂級對象
        isFirstChanged = true;
      };
    })(),

總結

  • 箭頭函數不會被call, bind等方法改變this指向
  • 在閉包中返回函數, 緩存變量時, 使用function進行返回函數的定義.


免責聲明!

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



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