### 函數 & 執行環境:
- 當函數被呼叫時,一個新的**執行環境**會被建立起來:
- **這部分先不要跟物件搞混**。
```
// 詞彙
Execution 執行
Context 上下文
```
- 每個執行環境(Execution context),都有自己的**變數環境**:
- 亦可參考到**外部環境**(outer environment)。
```
// 詞彙
variable environment 變數環境
outer environment 外部環境
```
### this
- 當我們產生執行環境時,JavaScript Engine 會幫我們產生我們從未宣告過的一個變數 - `this`。
- 在某些情況下,this 會根據環境決定它應該指向誰。
- 在以下範例,你會發現輸出的結果是 window
```js
function a() {
console.log(this);
}
a();
// outputs:
window
```
- 這代表什麼?這代表我們宣告了一個函數以後,在函數執行 `this`
它**仍然會指向全域物件**。
### 多宣告一個變數 b
```js
function a() {
console.log(this);
}
var b = function () {
console.log(this);
};
a();
b();
// 兩個輸出的結果都是一樣 -> window
```
- 嘗試建立物件:
```js
function a() {
console.log(this);
this.newvariable = `hello`;
}
var b = function () {
console.log(this);
};
a(); // window
console.log(newvariable); // hello
b(); // window
```
- 當我們呼叫函數時,this 指向全域物件,要能理解它,否則在開發上會發生很多奇怪的錯誤。
### 在物件中呼叫函數,this 會得到什麼?
- 指向到物件本身。
```js
var c = {
name: `The c object`,
log: function () {
console.log(this);
},
};
c.log();
// outputs:
{name: 'The c object', log: ƒ}
```
```
函數 a -> this 指向全域
函數 b -> this 指向全域
物件 c -> this 指向物件本身
```
- 在物件中的函數,產生 this 屬性會發生什麼事?
- 這時候 this 指向到物件內的函數中的屬性 name
```js
var c = {
name: `The c object`,
log: function () {
this.name = `update c object`;
console.log("this:", this);
},
};
c.log();
// outputs:
this: {name: 'update c object', log: ƒ}
```
### c 物件與 this 預期外的錯誤?
```js
var c = {
name: `The c object`,
// 透過 c.log() 呼叫,這邊的 this 是指向物件 c
log: function () {
this.name = `update c object`;
console.log(this);
// 表達式宣告函數 -> this 指向 window(全域)底下的 c 物件
var setname = function (newname) {
this.name = newname;
};
setname("Updated again! The c object");
// 第二次輸出,this 仍然指向物件 c
console.log(this);
},
};
c.log();
// outputs:
{name: 'update c object', log: ƒ} // 這邊 this 指向物件
{name: 'update c object', log: ƒ} // 這邊 this 指向全域
```
- 這裡使人感到困惑的點,是為何下一個 log 也 print 一個相同的結果。
### 解決方式-1:
- 將 this 賦值給一個變數:
```js
var c = {
name: `c is a object variable`,
log: function () {
var self = this;
self.name = `update c object!`;
console.log(self);
var setname = function (newname) {
self.name = newname;
};
setname("update again c object");
console.log(self);
},
};
c.log();
```
### 解決方式-2:
- **使用箭頭函數**,因為箭頭函數不會創建自己的 this,**而是繼承自外部作用域的 this**。
```js
const c = {
name: `The c is a object`,
log: function () {
this.name = `update object c!`;
console.log(this);
// 這邊改用 arrow function:
const setname = (newname) => {
this.name = newname;
};
setname("updated again object c");
console.log(this);
},
};
c.log();
```
### 後續:
- 本篇幅概念比較複雜一些,需要更深入的理解 this。