---
# System prepended metadata

title: '[JS] What is “this” in JavaScript? What does “this” refer to?'
tags: [JavaScript 學習紀錄]

---

###### tags: `JavaScript 學習紀錄`

# [JS] What is “this” in JavaScript? What does “this” refer to?

## Outline
- Simple call (直接的調用)
- As an object method (物件的調用)
- Arrow Functions (箭頭函式的調用)
- As a DOM event handler (DOM 物件調用)
- Strict mode (嚴格模式調用)
- `call`, `apply`, `bind` (強制綁定 `this` 的調用)
- As a constructor (建構式調用)


## Simple call
如果直接調用函式，此函式的 this 會指向 window，以下兩個範例都是直接調用函式，所以都是指向 window
#### Example 1: this refers to window object
```javascript=
window.name = 'window';
function callName() {
  console.log('call:', this.name);
}

callName(); //window
```

#### Example 2: 在function內宣並調用, simple call -> window
```javascript=
window.name = 'window';
function callName () {
  console.log('call:', this.name);

  // function 內的 function
  function callAgainName () {
    console.log('call again:', this.name);
  }
  callAgainName();
}

callName(); //"call:" "window"    //"call again:" "window"
```
小結: ==無論在哪一層，純粹的調用方式 this 都會指向 window==

## As an object method
如果 function 是在物件下被called，那麼 this 則會指向此object，無論 function 是在哪裡宣告
#### Example 1
```javascript=
var age = 18;

var person = {
  age: 28,
  displayAge: displayAge
}

function displayAge() {
    console.log(this.age);
    console.log(this);
}

displayAge(); // 18 //window

person.displayAge(); 
// 28, //{age: 28, displayAge: ƒ}, 在物件下呼叫，this 則是該物件 
```

#### Example 2: 把object裡面的function指給一個變數, 但還是用simple call 
```javascript=
window.age = 18;
var person = {
  age: 28,
  displayAge: function () {
    console.log(this.age);
    console.log(this);
  }
}

//物件內的 function指給一個變數
var callThisName = person.displayAge; 
callThisName(); // 18, window
```

#### Example 3: nested object
```javascript=
window.age = 18;

function displayAge() {
    console.log(this.age);
    console.log(this);
}

var person = {
    age: 28,
    displayAge: displayAge,
    nestedPerson: {
        age:40,
        displayAge: displayAge
    }
}

displayAge();        //18 //window
person.displayAge(); //28, //{age: 28, displayAge: ƒ}. this refers to the person object 
person.nestedPerson.displayAge(); //40 //{age: 40, displayAge: ƒ}. this refers to the nestedPerson object
```

## Arrow functions: they don’t have their “own” this
- 依據語彙環境的父層區域（parent scope）來綁定。白話的說，arrow function **定義位置**（不是呼叫順序）的上一層 this 代表誰，arrow function 內的 this 就代表誰
```javascript=
var person = {
    age:28,
    displayAge:function() {
        const displayAge2 = () => { 
            console.log(this.age);
            console.log(this);
        }
        displayAge2(); //arrow function->parent this
    }
}

person.displayAge(); //28, {age: 28, displayAge: ƒ}
```

## As a DOM event handler
- DOM 搭配 addEventListener 時，this 指的是觸發事件的元素。以下這段程式碼可以貼在任何網頁下的 Console，接下來點擊畫面上任何一區域，該區域則會加上紅線

#### Example 1: DOM + addEventListener, this 是 DOM boject
```javascript=
const box = document.querySelector('.box')
box.addEventListener('click', function(){
    console.log(this); // 這裡的 this 是 DOM box
})
```

#### Example 2: DOM + addEventListener + arrow function, this 是 parent 的 this
```javascript=
const box = document.querySelector('.box')
box.addEventListener('click', function(){
    console.log(this); // DOM box
    setTimeout(()=>{
        console.log(this); // DOM box. arror function->parent this
    },500)
})
```

## Strict mode: 讓simple call的 this 不再是全域 window, 需要給它this
- 現在會建議寫 JavaScript 的時候加入 'use strict'，這可以改正一些coding不良習慣，但也有可以因此導致專案無法運作，此時可以考慮將 'use strict' 加在函式內，避免影響過去的程式碼及相關套件
#### Example 1
```javascript=
window.age = 28;
function displayAge() {
  'use strict';
  console.log('call:', this.age);
}
displayAge();
// Uncaught TypeError: Cannot read properties of undefined (reading 'age')
```

#### Example 2:給 strict mode 一個this, object調用 or 綁定都可以
```javascript=
window.age = 38;
const person = {
  age :28,
  displayAge: function displayAge() {
    'use strict';
    console.log(this.age);
  },
}
person.displayAge(); //28. object call->this is person obj
person.displayAge.call({ age: 18 }); //18. 強制綁this
```

## 強制綁定 this
`call`, `bind`, `apply` 這三者都可以傳入新的 this 給予函式使用，使其作為 this 所指向的物件，三者僅是使用方法不同

#### `call` 
- **`fn.call(this, arg1, arg2..., argn)`**
    - 第一個參數：想要綁定的 this
    - 第二以後的參數：想要傳進目標函式的參數，如果目標函式中不需要參數則不要傳入即可
- 功能
    - 執行 function
    - 明確指定 this

Example 1: 強制綁定18,永遠的18歲！
```javascript=
var age = 28;
function callName() {
  console.log(this.age);
}

callName(); // 28
callName.call({age: 18});  // 18
```
Example 2: 除了傳入給定 this 的參數之外還可以傳入其他argument
```javascript=
var obj1 = {
  myName: 'obj 1',
  fn: function (message) {
    console.log(this.myName + ' ' + message);
  }
}

var obj2 = {
  myName: 'obj 2',
}

obj1.fn.call(obj2, 'Hello'); //obj 2 Hello
```

#### `apply`
- **`fn.apply(this, [arg1, arg2..., argn])`**
    - 第一個參數：想要綁定的 this
    - 第二個參數：與`call`類似, 只是第二個參數是陣列而且必須是陣列
- 功能
    - 同`call`
```javascript=
var obj1 = {
  myName: 'obj 1',
  fn: function (message) {
    console.log(this.myName + ' ' + message);
  }
}

var obj2 = {
  myName: 'obj 2',
}

obj1.fn.call(obj2, ['Hello']); //obj 2 Hello
```

#### `bind`
- **`fn.bind(this, arg1, arg2..., argn)`**
    - 第一個參數：想要綁定的this
    - 想要傳進目標函式的參數，如果目標函式中不需要參數則不要傳入即可
    - 回傳：回傳包裹後的目標函式
- 功能
    - 明確指定 this
    - 回傳一個包裹函式，當我們執行這個函式時，同時將arguments 一起帶進 Function 中
    - 無論函數怎麼被調用，原始函數的 this 在新函數將永遠與 bind 的第一個參數綁定起來, 只能綁一次的概念

Example 1
```javascript=
function fn() {
    console.log(this.a);
}

var bfn = fn.bind({a: 'Mark'});

var b2fn = bfn.bind({a: 'Rose'});

fn(); // undefind, 全域沒有定義a
bfn(); // Mark
b2fn(); // Mark. bind 只能使用一次！就算再綁Rose也沒用
```

Example 2: object call + `bind`
```javascript=
function fn() {
    console.log(this.a);
}

var bfn = fn.bind({a: 'Mark'});

var b2fn = bfn.bind({a: 'Rose'});

var obj = {a: 'John', fn: fn, bfn: bfn, b2fn: b2fn};

obj.fn(), obj.bfn(), obj.b2fn();
// John, Mark, Mark. object調用在bind過後會被取代
```

## As a constructor
在建構式下會 new 一個新物件，此時的 this 會指向新的物件
```javascript=
function TeamConstructor () {
  this.men = 'jamie'
}

class TeamConstructor {
    constructor(man) {
        this.man = man;
    }
}

var myTeam = new TeamConstructor();
console.log(myTeam.men); //jamie
```

## 整理
- Simple call: window
- As an object method: object本身
- Arrow Functions: parent this
- As a DOM event handler: DOM object
- Strict mode: 給它的this
- `call`, `apply`, `bind`: 強制綁進去的`this` 
- As a constructor: 建構式本身new object

## 總結
- ==Regular function: how is called ?==
- ==Arrow function: where is definded ?==


## Reference
[this: Simple call, Object method, DOM event handler, Constructor](https://developer.mozilla.org/zh-TW/docs/Web/JavaScript/Reference/Operators/this)
[Regular function v.s Arrow function](https://www.youtube.com/watch?v=dWZIPIc3szg)
[Strict mode](https://www.w3schools.com/js/js_strict.asp)
[call, apply, bind](https://developer.mozilla.org/zh-TW/docs/Web/JavaScript/Reference/Global_Objects/Function/call)