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
方法是作為回撥函式傳遞給其他方法或非同步操作(如 setTimeout
、Promise
的 then
或 catch
),那麼 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 例項。以下是三種方法的總結:
- 使用箭頭函式:最簡潔的方法,適合大多數情況。
- 顯式繫結
this
:透過.bind(this)
方法顯式繫結this
。 - 儲存
this
引用:在chat
方法中儲存this
引用,並在run
方法中使用該引用。
選擇一種適合你專案需求的方法,可以確保 this
正確地指向 Vue 例項。