owned this note
owned this note
Published
Linked with GitHub
# JavaScript 捉摸不定的 This
###### tags: `JavaScript`
`this` 大部份跟 `function` 怎麼宣告沒有關聯,跟怎麼**調用** `function` 比較有關。
```javascript=
var someone = '全域';
function callSomeone (){
console.log(this.someone);
};
callSomeone();
// 這邊是用 simple call 的方式調用 function
// 裡面的 this 會指向 window 中的 someone
// 所以這邊會印出 '全域'
const obj = {
someone: '物件',
callSomeone
};
obj.callSomeone();
// 這邊是 物件的方法調用
// 裡面的 this 會指向前面物件 obj 裡的 someone
// 所以這邊會印出 '物件'
const person = 'window';
function callPerson(){
console.log(this.person);
};
callPerson();
// 這邊是用 simple call 的方式調用 function
// 裡面的 this 會指向 window 中的 person
// 但變數 person 宣告時是用 const,const 不會污染全域變數
// 所以 window 裡面沒有變數 person
// 這邊結果會是 undefine
const obj2 = {
person: 'object',
callPerson
};
obj2.callPerson();
// 這邊是 物件的方法調用
// 裡面的 this 會指向前面物件 obj2 裡的 person
// 所以這邊會印出 'object'
setTimeout(callSomeone, 1000);
(callPerson)();
// 這 2 個調用方式也是 simple call
// 所以 this 會指向 window
// 結果會是 undefine
```
<br>
> 比較好記的方式:看 function 前面的物件是誰,this 就會指向該物件。
```javascript=
function callSomeone (){
console.log(this.someone);
};
const obj = {
someone: '物件',
callSomeone,
innerObj: {
someone: '內層物件',
callSomeone,
innermostObj: {
someone: '深處物件',
callSomeone,
}
}
};
obj.callSomeone();
// 這邊調用 callSomeone() 時前面的物件是 obj
// 所以裡面的 this 會指向前面 obj
// 這邊會印出 '物件'
obj.innerObj.callSomeone();
// 這邊調用 callSomeone() 時前面的物件是 innerObj
// 所以裡面的 this 會指向前面 innerObj
// 這邊會印出 '內層物件'
obj.innerObj.innermostObj.callSomeone();
// 這邊調用 callSomeone() 時前面的物件是 innermostObj
// 所以裡面的 this 會指向前面 innermostObj
// 這邊會印出 '深處物件'
```
<br>
## 影響 this 的語法
Javascript 有 3 種方法可以強制綁定 `this` 的指向,分別是:
- `call()`
- `apply()`
- `bind()`
### call()
當 `call()` 傳入參數後會立即執行 function。
```javascript=
var myName = 'window';
const obj1 = {
myName: 'object1'
};
const obj2 = {
myName: 'object2',
fn(){
console.log(this.myName);
}
};
obj2.fn.call(obj1); // 'object1'
```
另外,`call()` 除了 `this` 參數以外也可以代入其他參數。
```javascript=
var myName = 'window';
const obj1 = {
myName: 'object1'
};
const obj2 = {
myName: 'object2',
fn(msg){
console.log(msg + ', ' + this.myName);
}
};
obj2.fn.call(obj1, 'Hi'); // 'Hi, object1'
// 這裡第 1 個參數是要綁定的 this 參數
// 第 2 個參數是 fn() 的參數
```
### apply()
`apply()` 與 `call()` 非常相似,不同的是 `apply()` 除了要綁定的 `this` 參數之外是代入 array。
> fun.apply(thisArg, [argsArray])
```javascript=
var myName = 'window';
const obj1 = {
myName: 'object1'
};
const obj2 = {
myName: 'object2',
fn(msg1, msg2){
console.log(msg1 + ', ' + this.myName + '. ' + msg2);
}
};
obj2.fn.apply(obj1, ['Hi', 'How about you?']);
// 'Hi, object1. How about you?'
```
### bind()
`bind()` 也和 `call()` 相似,差別在於 `bind()` 不會馬上執行函式,而是回傳綁定好 `this` 的 function。
```javascript=
var myName = 'window';
const obj1 = {
myName: 'object1'
};
const obj2 = {
myName: 'object2',
fn(msg){
console.log(msg + ', ' + this.myName);
}
};
const newFn = obj2.fn.bind(obj1, 'Hi');
newFn();
// 'Hi, object1.
```
### 將 undefined、null 傳入 call()、apply()、bind()
當我們在執行 `call()`、`apply()`、`bind()` 時把綁定 this 的參數代入 undefined、null,這時 function 裡的 `this` 將會重新指向 `window`。
```javascript=
var myName = 'window';
const obj = {
myName: 'object',
fn(msg){
console.log(msg + ', ' + this.myName);
}
};
obj.fn.call(undefined, 'Hi'); // 'Hi, window'
obj.fn.apply(undefined, ['Hi']); // 'Hi, window'
const newFn = obj.fn.bind(null, 'Hi');
newFn(); // 'Hi, window'
// 'Hi, object1.
```
而在嚴謹模式下則會出錯。
```javascript=
'use strict'
var myName = 'window';
const obj = {
myName: 'object',
fn(msg){
console.log(msg + ', ' + this.myName);
}
};
obj.fn.call(undefined, 'Hi');
// Uncaught TypeError:
// Cannot read properties of undefined (reading 'myName')
```
<br>
## 箭頭函式的 this
箭頭函式本身沒有 this,箭頭函式的 this 會指向外層作用域的 this
```javascript=
var person = 'window';
const callPerson = () => {
console.log(this.person);
};
const obj = {
person: 'object',
callPerson
};
obj.callPerson();
// 箭頭函式的 this 會指向外層作用域的 this
// 這邊外層沒有作用域
// 所以這裡的 this 會指向 window
const obj2 = {
person: 'object2',
fn() {
(() => {
console.log(this.person);
})();
}
};
obj2.fn();
// obj2.fn 內的箭頭函式的 this 會指向 obj2.fn() 的 this
// 所以這邊會印出 'object2'
```
###### 參考資料
- [關於 JavaScript 的 this 各種用法與探討](https://hsiangfeng.github.io/javascript/20210403/2190440925/)
- [鐵人賽:JavaScript 的 this 到底是誰?](https://wcc723.github.io/javascript/2017/12/12/javascript-this/)
- [JavaScript This 系列文:this 與物件的關係](https://wcc723.github.io/javascript/2019/03/18/JS-THIS/)
- [JavaScript This 系列文:this 為什麼指向 window](https://wcc723.github.io/javascript/2019/03/21/this-why-window/)
- [透過練習題,摸熟 This 的運作](https://wcc723.github.io/development/2020/09/28/this-homework/)