第 0 章:前言與環境設定
JavaScript 是一門應用極廣的語言,可用於網頁前端互動、伺服器程式、桌面與手機 App 甚至物聯網裝置的開發。
在開始學習之前,建議你下載並安裝 Visual Studio Code
(VS Code) 作為主要編輯器,
這是一款免費且功能豐富的工具。
請至 nodejs.org 下載
Node.js,完成後在終端機中輸入 node -v 確認安裝成功。
撰寫以下程式檢查環境:
console.log("Hello World!");
若終端機中正確顯示 "Hello World!",則表示環境設置完成。
練習題: 撰寫函式 solve(),回傳字串 "Hello World!",
並利用 console.log() 輸出結果。
第 1 章:變數與資料型態
變數就像儲物櫃,用於存放各種資料;資料型態則定義了資料的形式。JavaScript 提供三種變數宣告方式:
var:傳統方式,但存在作用域提升(Hoisting)問題,容易造成錯誤,故不建議使用。let:區塊作用域變數,僅在所在區塊有效,能避免作用域混淆。const:區塊作用域常數,一經設定值便不可更改,適用於固定資料。
常見資料型態包括:
- Number:數字,如
42、3.14,可進行算術運算。 - String:字串,如
"hello",表示文字資料。 - Boolean:布林值,僅有
true與false,常用於條件判斷。 - Null:明確設定的空值,表示「無」。
- Undefined:變數宣告後未賦值時的預設值。
- Object:複合型資料,用於存放多個屬性與方法。
- Array:有序資料集合,本質上也是物件。
- Symbol:ES6 新增,表示獨一無二的值。
- BigInt:用來表示超過 Number 安全範圍的大整數。
練習題: 撰寫函式 solve(),在函式內使用 let 宣告變數(100)與 const
宣告常數(200),
然後回傳字串 "let: 100, const: 200"。
第 2 章:基礎輸入與輸出 (I/O)
輸入與輸出是程式與使用者間溝通的橋樑。使用 console.log()
可將訊息印出到終端機,協助你追蹤程式運作與除錯。
例如,計算 BMI 的公式為:BMI = weight / ((height/100)²)。
當身高以公分表示時,必須先除以 100 轉換成公尺,再進行計算。
練習題: 撰寫函式 solve(height, weight),根據上述公式計算
BMI 並回傳數值結果。
第 3 章:運算子與流程控制
運算子用於數學計算與邏輯比較,流程控制則決定程式根據條件如何執行。
基本運算子:例如 +、-、*、/、% 用於數學計算:
console.log(10 + 5); // 15
console.log(10 % 3); // 1
-
運算子
=用於賦值;==在比較時會自動轉換型別(例如 5 == "5" 為 true);===嚴格比較,只有型別和值都相同才回傳 true(例如 5 === "5" 為 false)。
=:
流程控制語法:
使用 if...else 根據條件決定執行區塊:
if (score >= 60) {
console.log("及格");
} else {
console.log("不及格");
}
使用 switch 進行多分支選擇,並搭配 break 防止落空執行:
switch (fruit) {
case "apple":
console.log("蘋果");
break; // 若無 break,則會繼續執行下一個 case
case "banana":
console.log("香蕉");
break;
default:
console.log("未知水果");
}
迴圈語法:
使用 for 或 while
重複執行程式;
continue 可跳過本次迴圈的剩餘程式,break 可中斷整個迴圈:
// 使用 continue:當 i === 2 時跳過
for (let i = 0; i < 5; i++) {
if (i === 2) continue;
console.log(i); // 輸出 0, 1, 3, 4
}
// 使用 break:當 i === 3 時中斷迴圈
for (let i = 0; i < 5; i++) {
if (i === 3) break;
console.log(i); // 輸出 0, 1, 2
}
練習題: 撰寫函式 solve(score),根據分數回傳等級:
分數 ≥ 90 為 "A",80–89 為 "B",70–79 為 "C",60–69 為 "D",其他回傳 "不及格"。
第 4 章:函式與箭頭函式
函式可封裝重複的邏輯,並透過參數接收外部輸入,最後回傳結果。這使得函式成為程式設計中的基本組件。 除了傳統函式外,ES6 提供的箭頭函式語法更簡潔,且 this 綁定固定。 下例示範傳統函式如何使用參數與回傳值:
function add(a, b) {
// a 與 b 為傳入參數,計算並回傳其和
return a + b;
}
console.log(add(3, 4)); // 輸出 7
練習題: 撰寫函式 solve(x),回傳 x 的平方,請使用多行箭頭函式語法。
第 5 章:遞迴與進階函式應用
遞迴是函式呼叫自身的一種技巧,常用於解決可以分解成相同問題的小問題。例如計算階乘: n! = n × (n-1)!,當 n 為 0 時定義 0! = 1。這種方法使問題得以逐步簡化。
function factorial(n) {
if (n === 0) return 1; // 終止條件
return n * factorial(n - 1); // 遞迴呼叫
}
console.log(factorial(5)); // 輸出 120
練習題: 撰寫函式 solve(n),利用遞迴計算並回傳 n 的階乘(n!)。
第 6 章:陣列 (Array)
陣列是一組有序資料的集合,就像購物清單。你可以使用數字索引存取陣列中的資料,並利用內建方法操作陣列。
常用方法包括:push()、pop()、shift()、unshift()、slice()、splice()、indexOf()、map()、filter() 與
reduce() 等。
陣列常用方法詳細介紹:
- push():將一個或多個元素加入陣列的尾端。就像你在購物清單的最後加上一項新物品,使得清單變得更長。
- pop():移除並回傳陣列中最後一個元素。就好比從堆疊的書本中取走最上面的一本,讓這本書不再出現在堆裡。
- shift():移除並回傳陣列中的第一個元素。這就像在排隊時,讓隊伍最前面的人先離開,剩下的人依序前移。
- unshift():在陣列開頭添加一個或多個元素。類似於在排隊時,突然有新朋友插隊到最前面,讓整個隊伍順序改變。
- slice():從陣列中擷取一段(根據起始和結束索引),並回傳一個新陣列,而不改變原陣列。就像從一整個蛋糕中切出一片來享用,但蛋糕本身仍保持完整。
- splice():用來插入、移除或替換陣列中的元素,直接修改原陣列。想像你在編輯購物清單時,把不需要的項目刪除或新增新項目,讓清單變得更符合當下需求。
- indexOf():返回某個元素在陣列中首次出現的位置,如果不存在則回傳 -1。就像在大房間裡找朋友的座位位置,找到了就告訴你是哪一個位置。
- map():對陣列中每個元素應用一個函式,並回傳一個新陣列。類似於用濾鏡對每一張照片進行處理,最終得到一組風格一致的新照片。
- filter():根據條件篩選陣列中的元素,回傳符合條件的新陣列。就像你從一籃水果中只挑出成熟的水果來吃。
- reduce():將陣列中的所有元素依序累計,最後回傳一個單一值。好比你將零錢一枚枚湊起來,最後得到一筆總金額。
範例:
let fruits = ["apple", "banana", "cherry"];
console.log(fruits[0]); // "apple"
fruits.push("date"); // 陣列變為 ["apple", "banana", "cherry", "date"]
console.log(fruits.indexOf("cherry")); // 2
練習題: 撰寫函式 solve(),建立陣列 ["apple", "banana", "cherry"] 並回傳第一個元素。
第 7 章:物件與 JSON
物件用於儲存多個相關資料,就像身份證記錄姓名、年齡與地址。你可以存取、修改物件的屬性,並定義方法來操作資料。 JSON(JavaScript Object Notation)是一種輕量級的資料交換格式,可將物件轉換成字串,方便儲存與傳輸。
範例:
let student = {
name: "John",
age: 30,
greet: function() { return "Hello, " + this.name; }
};
console.log(student.name); // "John"
console.log(JSON.stringify(student)); // 將物件轉換成 JSON 字串
練習題: 撰寫函式 solve(),建立物件 {name: "John", age:
30} 並回傳其 JSON 字串。
第 8 章:字串操作
字串用於表示文字資料,JavaScript 提供多種方法來操作字串,讓你可以檢查、轉換、分割或替換文字。
常用方法包括:length、toUpperCase()、toLowerCase()、slice()、split()、join()、indexOf()、includes()
與 replace()。
字串常用方法詳細介紹:
- length:屬性用來取得字串中的字元數。就好像數一數一段話裡有多少個字母或符號。
- toUpperCase():將字串中的所有字母轉換成大寫。類似於把小聲的話變成大聲喊出來。
- toLowerCase():將字串中的所有字母轉換成小寫。就像把大聲喊出的話,調低音量成為輕聲細語。
- slice():從字串中擷取一部分並回傳新的字串。就像從一張長條紙上剪下你想要的那一段,不影響原紙。
- split():根據指定分隔符,將字串分割成多個子字串,並回傳一個陣列。好比將一段話拆解成一個個單詞。
- join():將陣列中的所有元素合併成一個字串,並可指定分隔符。就像把一系列散落的拼圖塊拼接成一幅完整的圖畫。
- indexOf():回傳某個子字串在原字串中首次出現的位置,若找不到則回傳 -1。類似於在一本書中尋找某個關鍵詞首次出現的頁數。
- includes():檢查字串中是否包含特定子字串,返回 true 或 false。就像在菜單上確認是否有你喜歡的菜色。
- replace():用新的子字串取代原字串中符合條件的部分,回傳替換後的新字串。就好比在文章中修正錯誤,把錯別字改成正確的詞語。
範例:
let str = "hello world";
console.log(str.length); // 11
console.log(str.toUpperCase()); // "HELLO WORLD"
console.log(str.slice(0, 5)); // "hello"
console.log(str.split(" ")); // ["hello", "world"]
練習題: 撰寫函式 solve(),將字串 "hello world"
轉換為全大寫後回傳。
第 9 章:錯誤處理與除錯
錯誤處理能夠避免程式因錯誤而崩潰,並幫助你快速找到問題所在。你可以使用 try...catch 捕捉錯誤,
並利用 throw 主動拋出錯誤來中斷不合理的執行流程。
為何要用 break: 在 switch 陳述式中,若不使用 break,當某個 case 條件滿足後,程式會繼續執行後續所有 case,
這稱為「落空執行」,通常會導致意外結果,因此必須使用 break 來中斷。
範例一:主動拋出錯誤
function checkAge(age) {
if (age < 18) {
throw new Error("未滿 18 歲");
}
return "符合資格";
}
範例二:捕捉錯誤並判斷
try {
checkAge(16);
} catch (error) {
console.log(error.name); // "Error"
console.log(error.message); // "未滿 18 歲"
}
練習題: 撰寫函式 solve(),故意拋出一個錯誤,並用 try...catch
捕捉後回傳錯誤訊息 "意外錯誤"。
第 10 章:進一步的流程控制與錯誤捕捉補充
除了基本的流程控制與錯誤處理外,本章進一步說明:
- 為何在 switch 陳述式中必須使用 break(避免落空執行)。
- 如何在錯誤處理中根據 error.name 來判斷錯誤類型,進而做出不同處理。
switch (day) {
case 1:
console.log("星期一");
break; // 防止落空執行
case 2:
console.log("星期二");
break;
default:
console.log("其他");
}
try {
throw new Error("自訂錯誤");
} catch (e) {
if (e.name === "Error") {
console.log("自訂錯誤");
} else {
console.log("其他錯誤");
}
}
練習題: 撰寫函式 solve(),故意拋出一個自訂錯誤(例如 "自訂錯誤"),
在 catch 區塊中判斷錯誤名稱,若為 "Error" 則回傳 "自訂錯誤",否則回傳 "其他錯誤"。
第 11 章:非同步與 async/await
當程式需要等待長時間操作(例如網路請求或檔案讀取)時,非同步技術可以讓程式在等待時繼續執行其他任務。
Promise 表示一個尚未完成但未來會有結果的操作;而 async/await 語法使非同步程式碼看起來像同步程式碼,
其中 await 可等待 Promise 解決後再執行下一行程式碼。
範例:
async function fetchData() {
try {
let response = await fetch("https://api.example.com/data");
let data = await response.json();
return data;
} catch (err) {
console.error("錯誤:", err);
}
}
練習題: 撰寫 async 函式 solve(),模擬非同步操作(無需實際請求),直接回傳字串 "done"。
第 12 章:非同步進階與錯誤捕捉補充
除了基本的 async/await,本章進一步說明如何在非同步操作中捕捉錯誤,並處理多個非同步操作的錯誤情境。
當使用 await 等待 Promise 時,如果該 Promise 被拒絕,錯誤會傳至 catch 區塊。
你可以根據錯誤類型進行不同處理。
範例: 模擬兩個非同步操作,其中一個故意拋出錯誤:
async function processData() {
try {
let a = await Promise.resolve(10);
let b = await Promise.reject(new Error("非同步錯誤"));
return a + b;
} catch (err) {
return "錯誤捕捉:" + err.message;
}
}
processData().then(console.log); // 輸出 "錯誤捕捉:非同步錯誤"
練習題: 撰寫 async 函式 solve(),模擬兩個非同步操作,其中第一個回傳
5,第二個故意拋出錯誤,
使用 try...catch 捕捉後回傳錯誤訊息 "捕捉到錯誤"。
第 13 章:綜合應用與專案實作
當你掌握了前面所有知識後,便具備了獨立撰寫小程式的能力。此時你可以將變數、流程控制、函式、陣列、物件、字串、 錯誤處理與非同步技術結合起來,製作一個完整應用,例如簡易計算機、記事管理系統或猜數字遊戲。 這就像廚師利用各種食材製作一頓豐盛大餐,需要合理安排程式邏輯與資料流程。
練習題: 撰寫函式 solve(),回傳字串 "project
completed",模擬專案完成的成果。
第 14 章:其他必備知識與延伸資源
這份教材可能是你第一個接觸的程式教材,但絕對不會是最後一份!
除了上述內容外,還有一些進階概念對撰寫健全、可維護的程式非常重要,例如:
- 作用域與閉包: 了解變數的存取範圍以及函式如何捕捉外部變數,有助於保護資料與建立私有變數。
- Hoisting(提升): 變數與函式宣告會被提升至作用域頂部,但初始化不會,可能導致未賦值錯誤。
- 原型與繼承: 物件透過原型鏈共享屬性與方法,這是 JavaScript 繼承機制的基礎。
- 模組化: 使用 ES6 模組(import/export)將程式拆分成獨立單元,提高程式結構與重用性。
- 事件處理: 在瀏覽器中如何捕捉並處理使用者互動(如點擊、輸入等),是前端開發的重要基礎。
此外,持續參考以下延伸學習資源,能幫助你更深入瞭解 JavaScript:
延伸學習資源:
MDN Web Docs|
Stack Overflow|
FreeCodeCamp
- 自學網頁の嬰兒教材:JavaScript(一)—— 幫衣服工廠做個好用表單: https://codelove.tw/@howtomakeaturn/course/l3j5xk
- (影片)【javascript】3小時初學者教學: https://www.youtube.com/watch?v=yZwlW5INhgk
練習題: 撰寫函式 solve(),回傳一個 JSON 字串,
表示包含 "MDN"、"Stack Overflow" 與 "FreeCodeCamp" 三個推薦資源的陣列。