vue2專案中 箭頭函式和普通函式里面 this的指向有何不同?

龙陌發表於2024-10-28

vue2專案中 箭頭函式和普通函式里面 this的指向有何不同?

在 Vue2 專案中,箭頭函式和普通函式中的 this 指向有所不同。理解這種差異對於正確使用 Vue 元件內的方法非常重要。

普通函式中的 this

在 Vue 元件中,普通函式(也稱為函式宣告或函式表示式)中的 this 通常指向 Vue 例項。這意味著你可以在這些函式內部訪問元件的資料、屬性、方法等。

例如:

export default {
  data() {
    return {
      message: 'Hello, Vue!'
    };
  },
  methods: {
    logMessage() {
      console.log(this.message); // 輸出: Hello, Vue!
    }
  }
};

在這個例子中,logMessage 是一個普通函式,它的 this 永遠指向 Vue 例項,因此可以正常訪問 data 中的 message

箭頭函式中的 this

箭頭函式不會建立自己的 this 上下文,而是繼承父作用域的 this 值。這意味著在 Vue 元件的方法中使用箭頭函式時,this 不會指向 Vue 例項,而是指向定義該箭頭函式的作用域中的 this

例如:

export default {
  data() {
    return {
      message: 'Hello, Vue!'
    };
  },
  methods: {
    logMessage: () => {
      console.log(this.message); // 輸出: undefined 或其他值,取決於外部上下文
    }
  }
};

在這個例子中,logMessage 是一個箭頭函式,它的 this 指向的是定義該箭頭函式的作用域中的 this,而不是 Vue 例項。因此,this.message 會是 undefined 或者其他值,這取決於外部作用域中的 this

何時使用箭頭函式

  • 事件處理器:在某些情況下,你可能會在模板中直接使用內聯箭頭函式作為事件處理器。這樣做會導致 this 指向全域性物件(如瀏覽器環境下的 window),因此不推薦這樣做。

    <button @click="() => this.logMessage()">Click me</button>
    

    更好的做法是在 methods 中定義一個普通函式,並將其繫結到事件處理器。

    <button @click="logMessage">Click me</button>
    
  • 生命週期鉤子:Vue 的生命週期鉤子應該總是使用普通函式,以確保 this 正確地指向 Vue 例項。

    export default {
      mounted() {
        console.log(this.message); // 輸出: Hello, Vue!
      }
    };
    
  • 回撥函式:如果你需要在回撥函式中使用 this,並且希望它指向 Vue 例項,可以使用普通函式或者使用 .bind(this) 方法來顯式繫結 this

    export default {
      methods: {
        async fetchData() {
          await someAsyncFunction().then(function(response) {
            console.log(this.message); // 輸出: undefined
          }.bind(this));
          
          // 或者使用箭頭函式
          await someAsyncFunction().then((response) => {
            console.log(this.message); // 輸出: Hello, Vue!
          });
        }
      }
    };
    

總結來說,在 Vue2 專案中,為了確保 this 指向 Vue 例項,你應該在大多數情況下使用普通函式。只有在特定場景下,比如在回撥函式中保持 this 上下文一致時,才考慮使用箭頭函式。

如果在methods中有個chat方法,使用普通函式形式,裡面有一個 run方法也使用普通函式形式,run方法中使用this,那麼此時this的指向是?

在 Vue2 專案中,如果你在 methods 中定義了一個普通函式 chat,並且在這個 chat 方法中又定義了另一個普通函式 run,那麼 run 方法中的 this 指向取決於 run 函式是如何被呼叫的。

情況 1: 直接在 chat 方法中呼叫 run 方法

如果 run 方法是在 chat 方法內部直接呼叫的,那麼 run 方法中的 this 仍然會指向 Vue 例項。這是因為 run 方法繼承了 chat 方法的 this 上下文。

export default {
  data() {
    return {
      message: 'Hello, Vue!'
    };
  },
  methods: {
    chat() {
      function run() {
        console.log(this.message); // 輸出: Hello, Vue!
      }
      run();
    }
  }
};

在這種情況下,run 方法中的 this 指向 Vue 例項,因此可以正常訪問 data 中的 message

情況 2: run 方法作為回撥函式傳遞

如果 run 方法是作為回撥函式傳遞給其他方法或非同步操作(如 setTimeoutPromisethencatch),那麼 run 方法中的 this 將不再指向 Vue 例項,而是指向全域性物件(在瀏覽器環境中通常是 window)或其他上下文。

export default {
  data() {
    return {
      message: 'Hello, Vue!'
    };
  },
  methods: {
    chat() {
      function run() {
        console.log(this.message); // 輸出: undefined (在瀏覽器中)
      }

      // 作為 setTimeout 的回撥
      setTimeout(run, 1000);

      // 作為 Promise 的 then 回撥
      someAsyncFunction().then(run);
    }
  }
};

在這種情況下,run 方法中的 this 不再指向 Vue 例項,而是指向全域性物件 window,因此 this.message 會是 undefined

解決方法

為了確保 run 方法中的 this 始終指向 Vue 例項,你可以使用以下幾種方法:

1. 使用箭頭函式

箭頭函式不會建立自己的 this 上下文,而是繼承父作用域的 this 值。

export default {
  data() {
    return {
      message: 'Hello, Vue!'
    };
  },
  methods: {
    chat() {
      const run = () => {
        console.log(this.message); // 輸出: Hello, Vue!
      };

      // 作為 setTimeout 的回撥
      setTimeout(run, 1000);

      // 作為 Promise 的 then 回撥
      someAsyncFunction().then(run);
    }
  }
};

2. 顯式繫結 this

使用 .bind(this) 方法來顯式繫結 this

export default {
  data() {
    return {
      message: 'Hello, Vue!'
    };
  },
  methods: {
    chat() {
      function run() {
        console.log(this.message); // 輸出: Hello, Vue!
      }

      // 作為 setTimeout 的回撥
      setTimeout(run.bind(this), 1000);

      // 作為 Promise 的 then 回撥
      someAsyncFunction().then(run.bind(this));
    }
  }
};

3. 在 chat 方法中儲存 this 引用

chat 方法中儲存 this 引用,然後在 run 方法中使用這個引用。

export default {
  data() {
    return {
      message: 'Hello, Vue!'
    };
  },
  methods: {
    chat() {
      const self = this;

      function run() {
        console.log(self.message); // 輸出: Hello, Vue!
      }

      // 作為 setTimeout 的回撥
      setTimeout(run, 1000);

      // 作為 Promise 的 then 回撥
      someAsyncFunction().then(run);
    }
  }
};

透過這些方法,你可以確保 run 方法中的 this 指向 Vue 例項,從而正確地訪問元件的資料和方法。

如果run方法是在 requestAnimationFrame中呼叫呢?

在 Vue2 專案中,如果你在 methods 中定義了一個普通函式 chat,並且在這個 chat 方法中使用 requestAnimationFrame 呼叫另一個普通函式 run,那麼 run 方法中的 this 指向取決於 requestAnimationFrame 的呼叫方式。

情況分析

run 方法作為 requestAnimationFrame 的回撥函式時,run 方法中的 this 將不再指向 Vue 例項,而是指向全域性物件(在瀏覽器環境中通常是 window)。

示例程式碼

export default {
  data() {
    return {
      message: 'Hello, Vue!'
    };
  },
  methods: {
    chat() {
      function run() {
        console.log(this.message); // 輸出: undefined (在瀏覽器中)
      }

      requestAnimationFrame(run);
    }
  }
};

在這種情況下,run 方法中的 this 不再指向 Vue 例項,因此 this.message 會是 undefined

解決方法

為了確保 run 方法中的 this 始終指向 Vue 例項,你可以使用以下幾種方法:

1. 使用箭頭函式

箭頭函式不會建立自己的 this 上下文,而是繼承父作用域的 this 值。

export default {
  data() {
    return {
      message: 'Hello, Vue!'
    };
  },
  methods: {
    chat() {
      const run = () => {
        console.log(this.message); // 輸出: Hello, Vue!
      };

      requestAnimationFrame(run);
    }
  }
};

2. 顯式繫結 this

使用 .bind(this) 方法來顯式繫結 this

export default {
  data() {
    return {
      message: 'Hello, Vue!'
    };
  },
  methods: {
    chat() {
      function run() {
        console.log(this.message); // 輸出: Hello, Vue!
      }

      requestAnimationFrame(run.bind(this));
    }
  }
};

3. 在 chat 方法中儲存 this 引用

chat 方法中儲存 this 引用,然後在 run 方法中使用這個引用。

export default {
  data() {
    return {
      message: 'Hello, Vue!'
    };
  },
  methods: {
    chat() {
      const self = this;

      function run() {
        console.log(self.message); // 輸出: Hello, Vue!
      }

      requestAnimationFrame(run);
    }
  }
};

總結

無論你選擇哪種方法,關鍵是要確保 run 方法中的 this 指向 Vue 例項。以下是三種方法的總結:

  1. 使用箭頭函式:最簡潔的方法,適合大多數情況。
  2. 顯式繫結 this:透過 .bind(this) 方法顯式繫結 this
  3. 儲存 this 引用:在 chat 方法中儲存 this 引用,並在 run 方法中使用該引用。

選擇一種適合你專案需求的方法,可以確保 this 正確地指向 Vue 例項。

相關文章