[JavaScript Note] — 淺談 JavaScript #4

Introduction & 前言

這章節主要筆記關於 This 的一些淺談,剛學 JavaScript 時就常常聽到『你真的了解 This 嗎?』、『This 到底指的是什麼?』,剛好在 JavaScript 核心篇的一個章節提到 This ,課後終於小了解關於 This 的三兩事,如果沒有搞清楚,常常會在錯誤的作用域裡做事情呢,話不多說,下面就開始來認識認識 This 吧。

接下來的每一章,不免俗的都會來一句:

本篇文章一切皆為筆記作用,有任何錯誤及問題,歡迎理性指教及討論,詳情請查閱公開課程說明書。


Summary & 摘要

本系列將會淺談 JavaScript ,希望給未來自己當作筆記以及剛接觸 JavaScript 的夥伴們,甚至能帶點不一樣觀點或您沒聽過的觀點給大家,所以不會太過深入的討論。

關於淺談的主題將會大致分為下列幾項,項目可能會做更動

  1. JavaScript 執行環境及作用域

  2. 運算子、型別與文法

  3. 物件

  4. 關於 This 那些事

本章討論的幾個關鍵標題為下列幾項。

  1. This 是什麼?

  2. This 的特性

  3. 關於箭頭函式對 this 的影響


關於 This

This 是什麼?

關於 JavaScriptThis 其實上 Google 就會發現好多大神的文章,究竟為什麼 This 這麼重要呢?在相關文章中能看見,如果你搞清楚 This 你就能掌握到程式將會怎麼走,也能掌握程式在對的地方執行對的事情。

JavaScript 函式內的 this 關鍵字 表現,和其他語言相比略有差異。在嚴格模式與非嚴格模式下也有所不同。
通常,this 值由被呼叫的函式來決定。它不能在執行期間被指派,每次函式呼叫調用的值也可能不同。ES5 引入了 bind 方法去設置函式的 this 值,而不管它怎麼被呼叫。ECMAScript 2015 也導入了定義 this 詞法範圍的箭頭函式
— 擷至 MDN


This 的特性

原理或是理論的部分這邊就不過多的詳細描述,但是主要還是要說一些比較淺顯易懂的東西。關於 This 的特性有幾點:

  1. 不需宣告。

  2. 每個執行環境都有自己的 This 關鍵字。

  3. This 和 Function 如何宣告沒有關聯性,和被呼叫方式有關。

  4. 在嚴格模式下,與在簡易模式下很不同。

在我們打開網頁 F12 之後開啟 Sources 然後就能看見最一開始的 This 指的是 Windows,而隨著我們的 FunctionThis 的指向位置又會開始改變。

1
2
3
4
5
6
7
8
9
10
11
function moreThis() {
// ....
}

var student = {
name: 'Rex',
moreThis: moreThis,
}

student.moreThis();
// 前面宣告什麼的都可以不用注意 只要看呼叫的時候 student 就是那個 This

上面提到到所謂的 **嚴格模式(‘use strice’)**,在 JavaScript 裡有一個靜默的小錯誤,不至於影響程式進行將會被忽略不會跳出警告,而使用 嚴格模式(‘use strice’) 後將會直接看見,而 嚴格模式(‘use strice’) 也可以依照部分環境加入,意思就是這個 Function 我想要加入,另一個不要其實也可以。


2020.07.31 後更:

關於箭頭函式對 this 的影響

廢話前言

沒想到過了快一年才回來補充,最近剛好在挑戰六角學院的 JS 60 Day,有興趣可以看看我的文章 [Hexschool JS60 Training] — 60天 JavaScript 學徒試煉 Day1-30[Hexschool JS60 Training] — 60天 JavaScript 學徒試煉 Day31-60

在第三十九天練習時碰到的題目剛好跟之前的 JS核心 有相關,就補充在這邊啦!

ECMAScript6 - ES6

關於 ES6 的歷史,在這個系列前一章 [JavaScript Notes] — 淺談 JavaScript #3 有介紹到,這邊大致再帶過一次。

ES歷史

ES 又稱 ECMAScript,Script 代表著腳本,而 ECMAScript 提供了腳本語言需要遵守的規則、細節和規範, JavaScript 是實現 ECMAScript 的規範後所誕生出來的語言。簡單點來說就是一些可以讓你更簡單做事情的 Function 及 一些寫 Code 規範,更詳細的發展歷程可以點 傳送門 查看。

進入正題

這邊雖然大家可能已經知道箭頭函式是做什麼的,但還是要提一下,在剛學習 JS 一陣子後可能會開始發現很多很酷炫的寫法,比如常見的 箭頭函式解構字串模板…等等,以下為 箭頭函式 的範例:

1
2
3
4
5
6
7
8
9
10
// 舊寫法
var callName = function() {
return "I'm" + name;
}
// 箭頭函式 寫法
var callName = (name) => {
return "I'm" + name;
}

console.log(callName('王小明'))

上面可以看到 箭頭函式 取代了 function,雖然剛開始不是很習慣,但寫久了會變得很直覺,而且省下很多時間,身為工程師就必須能多懶就多懶,但是又要能懶到要處,讓人一看 Code 就知道你在寫蝦咪碗糕!

所以上面的例子我們還能這樣省:

1
2
3
4
5
6
// 箭頭函式 寫法
// 單一行陳述不需要 `{}`
// 此為舉例,如果需要 return 要自己帶入,並非可以省略並有 return 效果!
var callName = name => "I'm" + name;

console.log(callName('王小明'))

夠省吧!簡單的說只要記得下列幾點:

  1. function 改為 =>

  2. 帶有參數情況下,() 必須移到 => 箭頭前,且如果只有一個參數情況下,可省略 (),但若 沒有參數一個以上的參數 情況下,一定要帶括號!

  3. 單一行陳述不需要 {}

呼應主題 This

一篇好的文章結尾處是必須要呼應主題的,既然這篇文章是在講 This,那這邊就要再回來題 箭頭函式This 的影響。

首先我們先記得兩點關於 This 的差別:

  1. 傳統函式 => 依呼叫的方法而定

  2. 箭頭函式 => 綁定到其定義時所在的物件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
var name = '王小明';
var myFriend = {
name = '王大錘',
callName: function() {
console.log(this.name); // 王大錘
console.log(this); // myFriend
},
callName_2: () => {
console.log(this.name); // 王小明
console.log(this); // window
}
}

myFriend.callName();
myFriend.callName_2();

上述例子很清楚可以看見使用 箭頭函式This 會穿過原本的區塊直接指向外層的 window,這是因為 箭頭函式This 會綁定在 其定義時所在的物件,一般建立函式都是在 window 下,所以很自然就會指向 window,那要怎麼才能指向函式呢?

這邊再說一個比較好記的方式:

建立在物件內的函式,才會影響箭頭函式的 This

1
2
3
4
5
6
7
8
9
10
11
var fun = () => {
var fun2 = () => {
console.log(this);
}
var fun3 = {
fun: fun2,
xxx: 'xxx'
}
fun2(); // this => window
fun3.fun(); // this => fun3 Object
}

簡單說就是如果你的 function 有被物件包起來,這時候 This 指向的位置就不會是 window,因為你並不是建立在 window 上的,而是 Object 上的。

注意:上方示範的箭頭函式,適用於原本一般的函式。

call,apply,bind

關於這三個可以參考 JavaScript - call,apply,bind,會提到這三個屬性是因為在 箭頭函式 裡, This 是被綁定的,所以 call() 無法修改 Thiscall()apply() 呼叫箭頭函式只能傳入參數。

建構函式 Out

如果使用 new 運算子,箭頭函式 不可作為建構式使用;若使用於建構式,會在使用 new 時候拋出錯誤(範例為 MDN)。

1
2
var Foo = () => {};
var foo = new Foo(); // TypeError: Foo is not a constructor

DOM 監聽

記得前面提過的 This 會綁到 window 上嗎?所以如果拿來當 監聽事件 的作用會錯誤。

1
2
3
4
5
6
7
var name = document.getElementsById('name_input');
var changeName = () => {
console.log(this); // window
this.style.disable = 'true' // 錯誤
}

name.addEventListener('onkeyup', changeName, false);

上述例子為參考 卡斯伯老師 - 鐵人賽:箭頭函式 (Arrow functions) 修改。

小結

關於 箭頭函式 或是其他一些 ES語法糖 雖然很方便,但總還是會有需要注意的地方,但我們並無法都預先知道所有的錯誤, 就算知道了也可能很快就會忘記,所以最好的作法就是多練習,多犯錯!


Conclusion & 結論

本篇其實在原本就是打算做筆記之用途,因為實在有太多的大神已經寫了好多篇關於 This 的文章,沒有十足把握的話其實覺得多寫一篇關於 This 的文章真的是很沒意義,不過既然是自己要作為筆記用途,那就多少寫一些多少記一些囉。

更多關於 This 就等之後補上囉~


參考網站