最近看到網路上文章有人推這堂 Udemy 的 JavaScript 課程,然後就買下來了 The Complete JavaScript Course - From Zero to Expert
為什麼想上這堂課
由於整堂課有 69 小時,自己擷取的重點不一定符合所有階段的學習者,可能比較精簡 如果有看不懂的地方可以在下方留言,或建議還是來親自體驗一下這堂課 下方也會加入一些自己過往學習 JavaScript 的筆記
什麼是 ES6(ECMAScript6)?
- ECMAScript 是一個規範,JavaScript 實作了這個規範
- JavaScript 在 2015 年迎來了一次大更新,更新後的版本叫 ES6(ES2015),俗稱 Modern JavaScript
- 當你使用 Google 跟 StackOverflow 社群都找不到解答,閱讀這份文件ECMAScript也許會有助於你 debug
- 你可能聽過 Vue、React、Angular 這些不同的 JavaScript 套件或是框架,不過最後都會被打包成 JavaScript 在瀏覽器上運行。
- 隨著時代演進使用的框架可能會變,但熟悉 JavaScript 有助於未來與時俱進
ES6 新增了哪些語法
解構賦值
- 可以用精簡的語法來命名變數,可彈性修改變數名稱
|
|
- 可以用來定義預設值,由於從遠端取用資料可能會有預料外狀況(例如取不到資料變成 undefined),有預設值可以套用比較保險
|
|
- 可以不用另外宣告 temp 暫存變數,就可以互換變數值,很方便
|
|
- 讓取出巢狀內變數變得很簡單
|
|
Promise 語法
- 解決了 callback hell(難以維護跟閱讀的巢狀程式碼)
- ES7 有 async/await 更好讀
展開運算子
- 可以展開物件、淺拷貝、合併陣列、把可迭代的物件(string、array、array-like、Set、Map)跟非迭代物件 objects 變成陣列,且不用新增變數
|
|
其餘運算子
- 可以將陣列後方剩下的值存成一個陣列,解構賦值時好用(不會存取 skip, , 的 key 跟有出現過的 key)
|
|
箭頭函式
- 可以打較少的程式碼,提高程式碼可讀性
- 過往 this 值依照執行環境所有不同,不好判斷
- 而箭頭函式的 this 則是綁定定義他(而非呼叫他)的物件,看他身處在的 function scope 的 this 指向誰
- 白話文:箭頭函式沒有自己的 this,但可以使用父層的 this
模板字串
- 過往可以透過單引號或雙引號跟加號拼接字串,巢狀的時候需要雙引號包裹單引號(反過來則不行)
- 遇到拼接內容是 HTML 結構,換行需要加
\n
,使用上麻煩閱讀上也不容易 - 想寫縮寫或所有格(e.g. I’m cool, bac’s)的英文內容可能遇到需要用跳脫字元"I'm",而字串模板解決了上述不方便使用的問題
|
|
Enhanced Object Literals
- 屬性名跟本地變量名相同可以省略後面的冒號跟值
引入 class 類
- 作為 JavaScript 現有原型程式(prototype-based)繼承的語法糖
引入模組 Import and Export modules
- 方便管理程式碼之間的相依性,非同步載入(過往 require 是同步語法)
JavaScript 在網頁渲染時執行位置
- 瀏覽器渲染畫面流程:建立 DOM → 建立 CSSOM → 合併為 Render Tree → Layout(空間位置排版佈局) → Paint(繪製畫面,轉換成像素做呈現)
- 由於 JavaScript 在執行時,會停止渲染動作,阻塞 DOM 和 CSSOM 的建構過程
- 因此會建議把 script 放在 HTML 內容下方,也就是
</body>
前
|
|
- 如果為了效能想提早載入資源而希望把 script 放在
<head>
區塊,需要加一個defer
屬性避免阻擋渲染過程(DOM 還在建立) - 若使用
async
屬性,下載後會立刻執行但不保證順序,且請求回來後會停止解析,還是可能遇到 DOM 跟 CSSOM 還在生成,選不到元素,適合用在不會針對操作 DOM 的 script(e.g. Google Analytics)
JavaScript 變數命名限制
- 變數 variable 用來存取 value
- JavaScript 習慣小寫駝峰命名
yourName
,大寫開頭表示建構子 - 使用有意義的命名(e.g.
firstJob
、currentJob
而非job1
、job2
) - 不能用數字開頭當變數
- 不接受 - 符號(會當成減號)
- 變數內容只能包含數字、英文字、
_
、$
_
跟$
開頭的命名通常是有特別用途(e.g. 私有變數)- 不能使用 Reserved keywords(e.g. new、function),但
$new
或_funtion
是合法的 name
是 Reserved keywords,可以合法使用但可能有風險,寧願用firstName
等等
error msg 與 console.log
- SyntaxError: 語法結構錯誤(可能是括弧、拼字大小寫)
- ReferenceError: 引用錯誤(沒被定義、找不到檔案)
- RangeError: 超出參數範圍
- TypeError: 型別錯誤
- EvalError: eval()方法使用錯誤
- URIError: url 錯誤
- 如果 console.log 結果無法在瀏覽器的 dev tools 顯示出來,點右邊齒輪確認勾選狀況(一般會是勾 default value),可參考這篇 https://blog.csdn.net/xianyu_Padding/article/details/78013754
Data types 型別跟 Dynamic type
- Number(整數/浮點數)
- String(文字)
- Boolean(true/false)
- Object(物件/陣列/函式)
- Undefined(已宣告無定義)
- null(空值/empty value)
- Symbol(ES2015) unique 且無法被改變的 value
- BigInt(ES2020) 大整數 非 number 可以保存的 value
- JavaScript 在命名變數時不用手動定義型別,同一個變數可以賦予不同型別的值
- 變數可能原本是數字,後面變成字串,這也是 bug 產生的風險(但現在也有 typescript XD)
- 確認變數型別
typeof 變數
typeof 變數
得到的是固定的七種字串值:'undefined'
'object'
'boolean'
'number'
'string'
'function'
'symbol'
null v.s. undefined v.s. not defined
null
有宣告/有賦值 但會是一個空值 → 系統提示沒抓到元素 (e.g. array 當中 key 存在但值是空的)undefined
有宣告/沒賦值 → 系統提示沒有賦值not defined
沒宣告/沒賦值 → 系統提示沒有宣告
宣告變數方式 let、const、var
從 ES6 開始有了 const
跟 let
兩種新的呼叫方式
並且最小的區塊切分從 function
變成 block{},避免變數污染的發生
-
let
跟const
的差異 –let
的變數隨時可以用 = 重新賦值 –const
的變數無法用 = 重新賦值,適合用在常數,若為陣列或物件屬性的值還是可被改變 –const
若為 primitives,不能做 var += var 的操作 – 由於值的變更有產生 bug 的風險,基本上宣告會使用const
,若會重複賦值再用let
– 不會使用早期的宣告變數方式
var
,早期宣告變數方法只有var
搭配function
把作用域鎖在函式裡面,但若放在if else
等區塊語句,會讓var
宣告的變數洩漏到全域,造成變數污染 -
let
跟const
的共同處 – 同區塊上不能重複宣告 – 區塊內宣告不會洩漏到全域 -
作用域 –
var
在主程式區是全域變數,在function
內是區域變數 – 在 block 區塊語句(if、else、for、while 等)裡面用 var 宣告的變數,會洩漏到全域中,造成區域變數覆蓋全域變數 -
絕對不要直接命名而不使用
let
const
var
– 像是job = 'code'
– 沒有 scope,會變成全域變數,而且不在控管下,會造成記憶體管理問題
算數運算子 Arithmetic Operator
+ = * / ** % ++ --
加減乘除 指數 取餘數 遞增 遞減x++
跟++x
有執行順序的差別,前者先列印結果再相加,後者先相加再列印結果- 運算子還可以用做合併字串
字串1+ ' '+ 字串2
,但現在合併字串多用 template literal
指派運算子 Assignment operators
= += -= *= /= %=
- 將等號右邊的值拷貝給左邊的變數資料
比較運算子 Comparison operators
== === != !== > >= < <=
- 可以用來把判斷的結果存在變數
|
|
Operator precedence 運算子優先順序
-
MDN可以查詢,不用背有個概念即可
-
如果搞不懂順序,用()把確定要先執行的段落包起來,權重最高
-
解釋了為何程式可以正確執行類似有許多運算子卻不會誤判執行順序
|
|
- = 執行順序右到左
|
|
顯性轉型 Type Conversion
轉字串
toString()
可以將所有資料都轉換為字串 但是要排除 null 和 undefined(TypeError: Cannot read property ’toString’ )String()
可以將 null 和 undefined 轉換為字串(),因為他會先使用 valueOf 取得 primatives 值,然後再用 toString 轉為字串toString(value, radix)
可以轉 2 或 8 或 10 或 16 進位字串JSON.stringify()
轉成 JSON 字串""- undefined、function、symbol、具有循環參考(circular reference)的物件無法轉為 JSON 字串
|
|
- 陣列中某個元素的值為非法值則會以 null 取代
- 物件中的某屬性為非法值,則會排除這個屬性。
轉數字
parseInt(string, radix)
字串轉成數字,若第一個字符無法轉換為數字回傳 NaNNumber()
字串轉成數字,undefined 回傳 NaN,null 回傳 0,true 回傳 1,false 回傳 0
轉布林
Boolean()
如果沒傳值,或者是 0、-0、null、false、NaN、undefined、空字串會轉成 Boolean
隱性轉型 Coercion
運算子
- * /
會轉成數字'23' - '10' - 3 // 10
+
會轉成字串'23' + '10' // 2310
- 綜合
10 - 3 - 3 + '1' // 41
== === != !==
也會,可以看下方的嚴格的等號 v.s. 寬鬆的等號說明- || && 條件
ToNumber
強制轉成數字的邏輯
|
|
- 使用運算子強制轉型+new Date 取得時間戳記不是好方法
- 改 Date.now() 或 .getTime() 可讀性更好
if while for 內的() 跟!
- if (變數) 在 if 括弧裡的變數都會強制轉為 Boolean
- 程式沒寫好可能回傳 null、undefined、NaN 等,若當作條件判斷變成 false 容易造成判斷式錯誤,需要注意
|
|
- !(變數)也會讓變數強制轉型
|
|
Truthy & Falsy values
- Falsy 包含:
null、undefined、0、-0、空字串''、NaN(不等於自己)、false
- Big Int
0n
也是 Falsy 負數-1、非0的有效數字、空物件{}、空陣列[]、無作用函式function () {}
都是 true- 以下為 Falsy 值導致的錯誤設計範例(設計流程時需注意 falsy)
|
|
嚴格的等號=== v.s. 寬鬆的等號 ==
- 使用寬鬆的
==
,會發生會強制轉型,字串跟數字會相等 - 嚴格的等號會檢查資料型別,不會強制轉型
- 寬鬆的等號容易產生 bug,所以只會使用
===
跟!==
"0" == false
// true (“0"轉成數字 0,false 轉成 0)- null 與 undefined 在寬鬆相等下會強制轉型為彼此,因此是相等的,但不等於其他值。
- 若比較的對象是物件,使用 valueOf()(優先)或 toString() 將物件取得基本型別的值,再做比較。
有興趣可看這份MDN 一般相等比較表
* []
會先由 toString()
強制轉型為字串,再強制轉型為數字
AND OR ! 邏輯運算子
用於 if 條件增加判斷
&&
(AND)所有條件為 true 才會是 true||
(OR)有一個條件是 true 就是 true
|
|
用於 short-circuiting
- 可以做為 if 條件判斷的 argument,要執行哪一段程式
- 也可以套用
&&
或||
的邏輯,為變數賦值,讓程式碼更精簡 - && 可以檢查變數是否為 true,true 時才會執行後面的程式碼
- || 可以當作處理例外情況,當左邊變數有問題,使用右邊預設值
|
|
?? Nullish Coalescing
- 當左邊變數為 null 或 undefined 才會回傳右邊的值
- 若非 null 或 undefined,則回傳左邊的值
|
|
表達式 statements v.s. 陳述式 expressions
- 表達式:會回傳結果 e.g. 純值、變數、運算子、執行函式、正規表達式、函式表達式…
- 陳述式:會執行一些程式碼,可能是幾個單詞或是片段(不會是單一個字母),不會回傳結果 e.g. 宣告(var、function)、流程控制(block、if…else)、迴圈(for、while)、其它(import, export)
流程判斷
- if else
|
|
- Ternary Operator(條件運算子)
|
|
- switch(比較少用,看情況還是可以使用)
|
|
JavaScript 小歷史
|
|
JavaScript 和瀏覽器的相容性
- Backward compatibility: ES1 語法在現代瀏覽器還是相容的
- Forwards compatibility: 舊版本 IE8 瀏覽器不理解新版本 JavaScript 的規範 我們可以透過更新瀏覽器避免不相容
- ES5: fully supported in all browsers IE9(2011)
- ES6 → ES2021: well supported in all modern browsers, not in older ones. can use most features in production with transpiling and polyfilling 所以會使用 BABEL
- ES2022: ESNext future versions can use some features in production with transpiling and polyfilling
- 先學 Modern JavaScript 但還是需要知道過往 JavaScript 運作方式 e.g. const let v.s. var e.g. function construction v.s ES6 Class
- 關於Polyfills and transpilers
恭喜你看完這一篇 JavaScript 基礎知識複習(1),休息一下再往下一篇前進吧! JavaScript 基礎知識複習(2)