### 函數 & 執行環境: - 當函數被呼叫時,一個新的**執行環境**會被建立起來: - **這部分先不要跟物件搞混**。 ``` // 詞彙 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。