JS新賓樂

JS StarterLand

JavaScript 可用於網頁前端、伺服器、桌面應用、手機 App 及物聯網等多種領域。
本教材為無程式基礎的初學者設計,幫助你從零開始建立程式設計能力!

第 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:數字,如 423.14,可進行算術運算。
  • String:字串,如 "hello",表示文字資料。
  • Boolean:布林值,僅有 truefalse,常用於條件判斷。
  • 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("未知水果");
}

迴圈語法: 使用 forwhile 重複執行程式; 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 提供多種方法來操作字串,讓你可以檢查、轉換、分割或替換文字。 常用方法包括:lengthtoUpperCase()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 DocsStack OverflowFreeCodeCamp

練習題: 撰寫函式 solve(),回傳一個 JSON 字串, 表示包含 "MDN"、"Stack Overflow" 與 "FreeCodeCamp" 三個推薦資源的陣列。

前往練習區

線上練習系統