🧠 StudyCamp JavaScript 共學計畫:10 週部落格發表規劃

:brain: StudyCamp JavaScript 共學計畫:10 週部落格發表規劃

:sparkles: 前言:從 Python 到 JavaScript,擴展全端技能的探索旅程

這門課程是我在 StudyCamp 助學計畫中所申請的資源 —— The Complete JavaScript Course 2024。作為一名已有 Python 粗淺經驗的開發者,我期望深入理解 JavaScript 的核心知識,並將前端技能從零拓展到能實作專案的程度。

透過這 10 週部落格連載,我不僅學習,也同步整理筆記、設計實作專案,並逐步累積屬於自己的技術輸出與作品集。每篇內容皆會於 每週六晚上發佈,歡迎一同共學!


:books: 系列總覽與發佈進度表

週次 發佈時間 主題名稱 核心內容摘要
Week 1 8/10 JavaScript in the Browser: DOM and Events 初探 DOM 結構、事件監聽、互動操作,並完成互動式介面小專案。
Week 2 8/17 How JavaScript Works Behind the Scenes 深入記憶體管理、執行環境、Hoisting、Call Stack 等底層運作。
Week 3 8/24 Data Structures, Modern Operators and Strings 掌握物件、陣列、Set、Map 與 ES6 運算子(可選鏈、Null 合併等)。
Week 4 8/31 A Closer Look at Functions 學習 Function 表達式、箭頭函式、this 綁定、閉包與 callback。
Week 5 9/7 Working With Arrays [PROJECT] 用 map, filter, reduce 重構資料,並建構一份資料視覺化表格小專案。
Week 6 9/14 Numbers, Dates, Intl and Timers [PROJECT] 日期時間操作、格式國際化與 setTimeout/setInterval 實戰應用。
Week 7 9/21 Object-Oriented Programming (OOP) With JavaScript 物件導向基礎、class、constructor、繼承、封裝與多型。
Week 8 9/28 Mapty App: OOP, Geolocation, External Libraries, and More! [PROJECT] 用 OOP + Leaflet 製作地圖追蹤應用,整合外部資料庫與 API。
Week 9 10/5 Asynchronous JavaScript: Promises, Async/Await, and AJAX 非同步處理核心概念,fetch/axios 實作 API 資料串接專案。
Week 10 10/12 Forkify App: Building a Modern Application [PROJECT] 最終專案:完整建構食譜搜尋 App,整合 MVC 架構與模組化思維。

:red_exclamation_mark:備註:為確保內容完整吸收與落實,個別週數將附加程式碼片段與 Github 存放庫,並記錄 Debug 歷程與學習心得。


:card_index_dividers: 部落格架構設計(每篇文章模板)

每一篇文章都會採用以下架構,清晰呈現每週學習進度與心得:

:memo: 範例格式:

# Week 1:JavaScript in the Browser - DOM and Events

## 📌 本週學了什麼?

- DOM 結構與節點操作
- 事件監聽器(addEventListener)
- 滿足條件才觸發的互動邏輯
- 小專案實作:互動式待辦清單 UI

## 💡 關鍵概念拆解

- `document.querySelector()` vs `getElementById`
- `e.preventDefault()` 在表單中的角色
- Event Delegation 範例...

## 🔧 實作專案展示

🔗 GitHub Repo: [todo-list-demo](https://github.com/你的帳號/todo-list-demo)

![介面截圖](./images/week1-preview.jpg)

## 🧠 本週心得與挑戰

- 學會如何讓畫面變得「有感互動」
- 跨越了初次理解 `event.target` 的小挫折
- ...

## 📆 下一週預告

➡️ Week 2 將深入 JavaScript 的底層運作邏輯,看懂 event loop 與執行堆疊是成為進階者的關鍵。

:seedling: 計畫初衷與回顧

選擇這門課,是因為我過去在 Python 的後端學習中已累積一些基礎,期望可以透過這個深入的 JavaScript 課程,打開自己通往全端開發的大門。
透過每週產出、共學輸出,我將不只成為這段知識旅程的學習者,也會是參與社群回饋的一份子。


:hammer_and_wrench: 結語:打造學習作品集,走向實戰應用

在完成這 10 週計畫後,我會進一步整合:

  • :framed_picture: 圖片與介面截圖
  • :link: GitHub 專案連結
  • :clipboard: Markdown 筆記整理
  • :movie_camera: 若有機會,也會同步拍攝簡單教學影片(例如 Forkify App 專案)
2個讚

JavaScript 的魔法世界:從 DOM 操作到遊戲開發的奇妙旅程

前言:當代碼遇見瀏覽器

在學習 JavaScript 的路上,最讓我著迷的莫過於看到靜態的 HTML 頁面突然「活」了起來。這一切的魔法,都要從 DOM(Document Object Model)說起。

核心概念:DOM 與事件的雙重奏

DOM:瀏覽器內建的文件樹

DOM 並不屬於 JavaScript 本身,而是瀏覽器內建的功能。可以把 DOM 看成是一個讓 JavaScript 與瀏覽器內容互動的 API。正如課程中所說:

把 DOM 看成是一個可以讓 JavaScript 與之互動的 API

這個 API 將所有透過瀏覽器的內容物,以樹狀的架構解析。每個 HTML 元素都變成了一個可以被 JavaScript 操控的節點。

// 透過 DOM API 選取元素
const element = document.getElementById('myElement');
const elements = document.getElementsByClassName('myClass');

// 操作元素內容和樣式
element.textContent = '新的內容';
element.style.backgroundColor = 'blue';

事件:讓網頁有了靈魂

如果說 DOM 是舞台,那事件就是讓演員開始表演的導演。透過事件監聽器,我們可以:

  • 監聽鍵盤按鍵(keydown, keyup)

  • 捕捉滑鼠動作(click, mouseover)

  • 響應表單輸入(input, change)

element.addEventListener('click', function(event) {
    // 這裡是回調函數,當事件觸發時執行
    console.log('元素被點擊了!');
});

實戰經驗:貪食蛇遊戲的啟發

setInterval:遊戲的心跳

在製作 DOM 版本的貪食蛇遊戲時,我深刻體會到 setInterval 的重要性。它就像是遊戲的「心跳」:

// 啟動遊戲循環
this.gameLoop = setInterval(() => this.update(), 200);

這行簡單的代碼創造了遊戲的時間概念:

  • 每 200ms 執行一次 update()

  • 讓靜態的蛇開始移動

  • 持續檢測碰撞和食物

  • 即時更新畫面

關鍵洞察setInterval(() => this.update(), 200) 的具體動作是:

  1. 瀏覽器註冊計時器

  2. 每 200ms 將回調函數加入任務佇列

  3. 事件循環檢查主線程空閒時執行

  4. 重複這個過程,形成持續的動畫

unshift:陣列操作的巧思

在處理蛇的移動時,unshift() 方法展現了其獨特價值:

// 計算新蛇頭位置
const newHead = {
    x: this.snake[0].x + this.direction.x,
    y: this.snake[0].y + this.direction.y
};

// 在陣列開頭加入新蛇頭
this.snake.unshift(newHead);

// 如果沒吃到食物,移除尾巴保持長度
if (!eatFood) {
    this.snake.pop();
}

這個設計讓蛇的移動邏輯變得直觀:索引 0 永遠是蛇頭,新的身體節點自然地推入陣列前端。

超越 DOM:Canvas API 的視覺盛宴

從 DOM 到 Canvas 的跨越

雖然 DOM 操作能創造出功能完整的遊戲,但當我接觸到 Canvas API 時,發現了一個全新的世界。Canvas 讓我們能夠:

  • 繪製複雜的圖形和動畫

  • 實現高性能的視覺效果

  • 創造物理模擬和數學可視化

簡諧運動:數學與視覺的完美結合

在 Canvas 上實現簡諧運動時,我體會到了數學公式如何轉化為視覺藝術:

// 簡諧運動的核心公式
const x = A * Math.cos(omega * t + phi) * damping;

// 轉換為 Canvas 座標
const px = centerX + x;
ball.style.transform = `translate(${px}px, -50%)`;

更令人驚艷的是 Lissajous 圖形,它展示了兩個簡諧運動如何組合成複雜的軌跡:

// X 和 Y 方向的簡諧運動
const lxX = centerX + R * Math.cos(fx * omega * t);
const lxY = centerY + R * Math.sin(fy * omega * t + phaseDiff);

技術架構:API 的層次理解

瀏覽器 API 的分工合作

通過這次學習,我理解了瀏覽器 API 的層次結構:

  1. DOM API:管理文件結構和元素

    • document.getElementById()

    • element.addEventListener()

    • element.style.property

  2. Canvas API:控制像素級繪圖

    • canvas.getContext('2d')

    • ctx.arc(), ctx.lineTo()

    • ctx.fillStyle, ctx.stroke()

  3. Web APIs:提供各種瀏覽器功能

    • setInterval(), requestAnimationFrame()

    • localStorage, fetch()

JavaScript 運行時的概念

課程中提到的重要概念:JavaScript 的整體運行可以分為兩部分:

  • JavaScript 核心:語言本身的語法和功能

  • JavaScript Runtime:與瀏覽器互動的環境,DOM 就在其中

這個理解幫助我認識到 JavaScript 不僅僅是一門語言,更是一個與瀏覽器深度整合的開發平台。

實踐心得與技巧分享

1. 事件處理的最佳實踐

// 使用箭頭函數保持 this 綁定
setInterval(() => this.update(), 200);

// 而不是
setInterval(function() { this.update(); }, 200); // this 會指向 window

2. 性能優化的考量

  • 使用 transform 而非直接修改 lefttop

  • requestAnimationFramesetInterval 更適合動畫

  • 適時清理事件監聽器和計時器

3. 調試技巧

在開發過程中,將遊戲對象暴露到全域作用域是很有用的調試技巧:

// 讓 game 對象可在 console 中訪問
window.game = game;

// 然後在 console 中可以執行:
// game.score
// game.pauseGame()
// setGameSpeed(50)

結語:從靜態到動態的進化

這次的學習讓我深刻體會到 JavaScript 與瀏覽器 API 的強大。從簡單的 DOM 操作到複雜的 Canvas 動畫,從基礎的事件處理到遊戲循環的設計,每一步都讓我對前端開發有了更深的理解。

DOM 和事件不僅僅是技術概念,它們是連接用戶與程式的橋梁。當我們熟練掌握這些工具時,就能創造出真正互動、有趣且實用的 Web 應用。

未來的路上,我期待探索更多瀏覽器 API,如 Web Audio、WebGL、Service Workers 等,讓 Web 應用的可能性變得無限廣闊。


學習 JavaScript 就像學習一門藝術,DOM 和事件是這門藝術的基本功。掌握了它們,我們就能在瀏覽器這張畫布上創作出無限可能。

3個讚

JavaScript 核心概念精華重點

1. JavaScript 引擎與運行環境 (JavaScript Engine & Runtime)

JavaScript 引擎

  • 定義: 執行 JavaScript 代碼的程式

  • 知名引擎: Google V8 (Chrome, Node.js)

  • 核心組件:

    • Call Stack: 執行代碼的地方,使用執行上下文

    • Memory Heap: 存儲物件的非結構化記憶體池

代碼執行過程

  1. 解析 (Parsing): 將代碼轉換為抽象語法樹 (AST)

  2. 編譯 (Compilation): 使用即時編譯 (JIT) 將 AST 編譯為機器碼

  3. 執行 (Execution): 在 Call Stack 中執行

  4. 優化 (Optimization): 背景持續優化代碼

2. 執行上下文與調用堆疊 (Execution Context & Call Stack)

執行上下文

  • 全域執行上下文: 頂層代碼的執行環境

  • 函式執行上下文: 每個函式調用都會創建新的執行上下文

執行上下文組成

  1. 變數環境 (Variable Environment): 儲存變數和函式聲明

  2. 作用域鍊 (Scope Chain): 外部變數的參照

  3. this 關鍵字: 特殊變數

調用堆疊運作

// 範例
const name = 'Jonas';
function first() {
    const a = 1;
    second();
}
function second() {
    const b = 2;
}
first(); // 創建執行上下文並推入堆疊

3. 變數提升 (Hoisting) 與暫時性死區 (TDZ)

變數提升行為

聲明類型 提升 初始值 作用域
function :white_check_mark: 實際函式 區塊 (嚴格模式)
var :white_check_mark: undefined 函式
let/const :cross_mark: (TDZ) 未初始化 區塊

暫時性死區 (TDZ)

console.log(job); // ReferenceError
const job = 'teacher'; // TDZ 結束

TDZ 存在原因:

  • 避免使用未初始化變數造成的錯誤

  • 確保 const 變數正確運作

4. 作用域與作用域鍊 (Scope & Scope Chain)

作用域類型

  1. 全域作用域: 頂層代碼,可在任何地方訪問

  2. 函式作用域: 函式內部聲明的變數

  3. 區塊作用域: 僅適用於 let/const

作用域鍊

  • 內層作用域可訪問外層作用域的變數

  • 詞彙作用域: 基於代碼寫入位置決定

  • 變數查找:由內向外查找,直到找到或報錯

const myName = 'Jonas';
function calcAge() {
    const age = 30;
    function greet() {
        console.log(`${myName} is ${age} years old`); // 可訪問外層變數
    }
    greet();
}

5. this 關鍵字

this 指向規則

  1. 方法調用: 指向調用的物件

  2. 一般函式: undefined (嚴格模式) 或 window

  3. 箭頭函式: 繼承父級作用域的 this

  4. 事件監聽: 指向綁定的 DOM 元素

const person = {
    name: 'Jonas',
    greet() {
        console.log(this.name); // 'Jonas'
        
        const arrowFunc = () => {
            console.log(this.name); // 'Jonas' (繼承外層 this)
        };
        
        function regularFunc() {
            console.log(this.name); // undefined
        }
    }
};

6. 一般函式 vs 箭頭函式

重要差異

特性 一般函式 箭頭函式
this 有自己的 this 繼承父級 this
arguments 有 arguments 物件 沒有
提升 依聲明方式而定 依聲明方式而定

最佳實踐

  • 永遠不要用箭頭函式作為物件方法

  • 在需要繼承 this 的情況下使用箭頭函式

7. 記憶體管理

記憶體生命週期

  1. 分配: 創建變數時分配記憶體

  2. 使用: 讀取/寫入/更新值

  3. 釋放: 不再需要時釋放記憶體

儲存位置

  • 原始值: 存在 Call Stack (執行上下文中)

  • 物件: 存在 Memory Heap

  • 物件參照: 存在 Call Stack,指向 Heap 中的物件

垃圾回收 (Garbage Collection)

  • 標記清除演算法 (Mark-and-Sweep):

    1. 標記階段: 標記可達的物件

    2. 清除階段: 刪除不可達的物件

記憶體洩漏預防

  • 清理不需要的事件監聽器和計時器

  • 避免聲明大型全域物件

8. 核心特性總結

JavaScript 的特點

  • 高級語言: 有抽象層,自動記憶體管理

  • 即時編譯: JIT 編譯提高效能

  • 多範式: 支援程序式、物件導向、函式式編程

  • 原型繼承: 基於原型的物件導向

  • 一級函式: 函式可作為值傳遞

  • 動態型別: 執行時確定變數類型

  • 單執行緒: 一次只能執行一件事

  • 非阻塞: 透過事件循環實現併發

關鍵原則

  1. 理解執行上下文的創建和堆疊

  2. 掌握作用域鍊的查找機制

  3. 正確使用 this 關鍵字

  4. 避免記憶體洩漏

  5. 選擇正確的函式類型

1個讚

下面用「觀念→規則→情境→範例→常見坑」的方式,把 JavaScript 的 this 和 Python 的 self 做一個完整對照。

一句話重點

  • Python 的 self 是「顯式參數」:只是慣例名稱,誰當第一個參數都行(例如 selfme),它在呼叫時會由直譯器自動傳入實例。

  • JavaScript 的 this 是「關鍵字 + 呼叫時決定的綁定」:不是參數,值取決於「函式是怎麼被呼叫的」,而不是在哪裡定義。箭頭函式是少數例外,this 由外層詞法作用域決定。


核心差異對照表

面向 JavaScript this Python self
本質 語言關鍵字、非參數 普通變數名(慣例用 self),是方法的第一個參數
綁定時機 呼叫當下 根據呼叫型式決定;同一函式不同呼叫方式 this 可能不同 定義固定:方法被呼叫時,直譯器會把實例當作第一參數傳入
可否改名 不可 可(但強烈建議用 self
常見規則 4 大規則 + 箭頭函式:new 綁定、明確綁定(call/apply/bind)、隱式綁定(物件方法呼叫)、預設綁定(嚴格模式為 undefined,非嚴格模式為全域物件)、箭頭函式取外層 this 無「規則」概念:誰是接收者就傳誰(obj.method() 等於 Class.method(obj)
方法脫鉤 容易「丟失 this」,需要 bind 或箭頭函式救援 方法有 bound method 概念,脫鉤後仍記住實例
靜態/類方法 static 方法裡的 this 指向「類本身」(呼叫者),仍是呼叫時決定 @staticmethod 沒有 self@classmethod 第一參數是 cls(類)
建構/初始化 new 建立物件並把 this 綁到新物件上;若遺漏 new 會出事 __init__(self, …) 由直譯器建立實例並傳入 self
模組頂層 ES Modules 頂層 thisundefined;非模組腳本頂層 this 是全域物件(瀏覽器為 window this,頂層就是模組命名空間

綁定規則(JavaScript)

  1. new 綁定
    new Foo() 內的 this 指向新物件。

  2. 明確綁定
    fn.call(obj, …)fn.apply(obj, …)fn.bind(obj) 指定 this = obj

  3. 隱式綁定
    obj.fn() 內的 this 指向 obj(點號左邊的值)。

  4. 預設綁定
    單獨呼叫 fn():嚴格模式 this = undefined;非嚴格模式 this = 全域物件

  5. 箭頭函式(詞法綁定)
    () => {} 沒有自己的 this,會沿用外層的 this

Python 沒有這些規則——方法就是函式,第一個參數拿來接「實例」,如此而已。


情境對照與示例

1) 一般實例方法

JavaScript

class Counter {
  constructor() { this.count = 0; }
  inc() { this.count += 1; }
}

const c = new Counter();
c.inc(); // this === c

Python

class Counter:
    def __init__(self):
        self.count = 0
    def inc(self):
        self.count += 1

c = Counter()
c.inc()  # self 是 c

→ 用法相似:this.xself.x。差別在 JS 的 this 是關鍵字、Python 的 self 是顯式參數。


2) 方法脫鉤(callback / 指標傳遞)

JavaScript:容易丟失 this

class Counter {
  constructor() { this.count = 0; }
  inc() { this.count += 1; }
}

const c = new Counter();
const f = c.inc;
f();             // 嚴格模式:this = undefined → 例外或無效
f.call(c);       // OK
const g = c.inc.bind(c);
g();             // OK,永久綁定

Python:bound method 會記住實例

class Counter:
    def __init__(self):
        self.count = 0
    def inc(self):
        self.count += 1

c = Counter()
f = c.inc
f()  # OK,f 持有已綁定的 self=c


3) 回呼與事件處理

JavaScript

class Timer {
  constructor() { this.ticks = 0; }

  // 用箭頭函式保住外層 this
  start() {
    setInterval(() => { this.ticks += 1; }, 1000);
  }

  // 若用一般函式就需要 bind
  start2() {
    setInterval(function() { this.ticks += 1; }.bind(this), 1000);
  }
}

Python(以閉包寫回呼,直接用 self)

import threading

class Timer:
    def __init__(self):
        self.ticks = 0
    def start(self):
        def tick():
            self.ticks += 1
            threading.Timer(1, tick).start()
        tick()


4) 靜態方法 / 類方法

JavaScript

class Example {
  static whoAmI() { return this; } // 呼叫者(類本身)
}
Example.whoAmI() === Example; // true

Python

class Example:
    @staticmethod
    def sm():      # 無 self/cls
        return "no implicit receiver"
    @classmethod
    def cm(cls):   # 類本身
        return cls

對照:JS 的 static 方法裡常用 this 代表「類」,Python 用 @classmethodcls


5) 建構與初始化

JavaScript

function Person(name) {
  // 需要 new
  this.name = name;
}
const a = new Person('Ada');

// 忘了 new(嚴格模式會錯、非嚴格會汙染全域)
const b = Person('Alan'); // 問題!

Python

class Person:
    def __init__(self, name):
        self.name = name

a = Person('Ada')  # 一律正確,沒有「忘了 new」的坑


心智模型(幫你在腦中放對盒子)

  • 把 Python 的方法看成「普通函式 + 第一參數」:當你寫 obj.method(),其實是語法糖,等價於 Class.method(obj)。所以 self 徹底「明白可見」且穩定。

  • 把 JavaScript 的函式看成「可被多種方式呼叫」this 像是「多插槽電源」,插在誰身上就供應誰;因此 呼叫形式obj.fn() / fn.call(obj) / new Fn() / 單獨 fn() / 箭頭函式)才是關鍵。


常見坑位清單(JavaScript)

  1. 方法當回呼傳遞,this 丟失
    解法:bind、用箭頭函式包起來、或在建構時把方法定義成箭頭函式成為類欄位。

  2. 忘記 new(在建構函式風格中)
    解法:用 class 語法或在函式內檢查 new.target

  3. 嚴格模式差異
    單獨呼叫下,嚴格模式 this = undefined,非嚴格是全域物件。

  4. ES Module 頂層 thisundefined
    不要依賴頂層 this,改用明確的模組匯出或變數。

  5. DOM 事件處理
    element.addEventListener('click', function(){ console.log(this); }); 中的 this 是該 element;若改成箭頭函式,this 將取自外層,不會是元素。


速查對照(由 JS 轉到 Python/由 Python 轉到 JS)

  • JS this.x ≈ Python self.x

  • JS 要小心「呼叫方式」;Python 幾乎不用擔心,因為 self 是顯式參數且 bound method 會記住實例。

  • JS 靜態方法用 static,內部可用 this 指類;Python 用 @classmethodcls

  • JS 用箭頭函式保留外層 this;Python 直接在閉包裡用 self

  • JS 忘記 new 會出事;Python 不會有這個問題。


小型對照專案(完整示例)

JavaScript

class Store {
  constructor() {
    this.items = [];
    // 方式 A:方法正常定義,但使用時要注意綁定
    this.add = this.add.bind(this); // 綁一次,之後可安全當回呼
    // 方式 B:類欄位 + 箭頭,天生綁外層 this
    // this.add = (item) => { this.items.push(item); };
  }
  add(item) { this.items.push(item); }
}

const s = new Store();
['A','B','C'].forEach(s.add);    // OK,因為上面 bind 過
console.log(s.items);            // ["A","B","C"]

Python

class Store:
    def __init__(self):
        self.items = []
    def add(self, item):
        self.items.append(item)

s = Store()
for f in [s.add, s.add, s.add]:
    f('A')  # bound method,無需手動綁定
print(s.items)  # ['A', 'A', 'A']


結論

  • 日常物件導向使用 上,thisself 看起來很像:都用來指向目前的實例。

  • 關鍵差異 在於:self 是顯式參數與語法糖的結果,穩定、可預期this 則是 呼叫時才決定、容易在回呼/脫鉤時遺失,需要 bind 或箭頭函式來穩住。

  • 牢記 JS 的 4 大綁定規則 + 箭頭函式詞法綁定,你就能把兩者的差異完全吃透。

1個讚

一次搞懂 JavaScript 現代語法:解構、展開、邏輯運算與物件技巧大全

JavaScript 在 ES6 之後陸續引入了許多強大的語法糖,讓程式碼更簡潔、更好讀,也大幅提升了開發效率。本文將整理 從陣列解構到物件操作 的一系列現代語法,並搭配範例逐步拆解,幫助你快速上手。


1. 陣列解構(Array Destructuring)

陣列解構允許我們直接從陣列中取值並賦予變數,而不需要一個一個用索引存取。

:key: 重點特性:

  • 不改變原始陣列

  • 可以跳過元素

  • 可用來交換變數值

  • 可從函式返回多值中直接取值

  • 支援巢狀解構

  • 支援預設值

:white_check_mark: 範例:

const arr = [2, 3, 4];
const [x, y, z] = arr;
// x=2, y=3, z=4

let a = 1, b = 2;
[a, b] = [b, a]; // 輕鬆交換變數


2. 物件解構(Object Destructuring)

物件解構使用大括號 {} 來從物件中取值,變數名稱需與屬性名稱相符。

:key: 進階用法:

  • 重新命名變數

  • 設定預設值

  • 巢狀物件解構

  • 函式參數直接解構

:white_check_mark: 範例:

const person = { name: "Alice", age: 25 };
const { name: userName, age = 18 } = person;
// userName="Alice", age=25


3. 展開運算子(Spread Operator ...

展開運算子可以將可迭代元素展開成單獨值。

:key: 用途:

  • 合併/複製陣列

  • 傳遞多個參數給函式

  • 物件展開(ES2018+)

:white_check_mark: 範例:

const arr1 = [1, 2];
const arr2 = [3, 4];
const merged = [...arr1, ...arr2]; // [1,2,3,4]


4. Rest 模式(Rest Pattern ...

與展開運算子相反,Rest 模式會「收集剩餘元素」。

:key: 用途:

  • 陣列/物件解構收集剩餘值

  • 函式接受不定數量參數

:white_check_mark: 範例:

const [first, ...others] = [1, 2, 3, 4];
// first=1, others=[2,3,4]

function sum(...nums) {
  return nums.reduce((a,b)=>a+b,0);
}


5. 邏輯運算子與短路特性(AND / OR)

JavaScript 的 ||&& 不只處理布林值,它們會依據「短路求值」回傳實際值。

  • OR (||):回傳第一個「真值」或最後一個值

  • AND (&&):回傳第一個「假值」或最後一個值

:white_check_mark: 範例:

console.log(0 || "default"); // "default"
console.log(5 && "ok"); // "ok"


6. 空值合併運算子(Nullish Coalescing ??

只在值為 null 或 undefined 時才使用預設值。

:white_check_mark: 範例:

console.log(0 ?? 10);  // 0 (保留有效值)
console.log(null ?? 10); // 10


7. 邏輯賦值運算子(ES2021)

結合邏輯運算子與賦值,讓程式更簡潔。

  • ||=:僅在變數為 falsy 時賦值

  • ??=:僅在變數為 nullish 時賦值

  • &&=:僅在變數為 truthy 時賦值

:white_check_mark: 範例:

let count = 0;
count ||= 5; // 5
let data = null;
data ??= "default"; // "default"


8. 足球挑戰:綜合應用

在實戰挑戰中,這些語法被用於處理比賽數據:

  • 陣列解構 → 分離球員與守門員

  • Rest → 收集剩餘場上球員

  • Spread → 合併替補球員

  • for-of + entries() → 獲取索引與值

這展現了 現代 JS 語法能大幅簡化程式 的威力。


9. 物件實字的增強(ES6)

物件定義也獲得三項強化:

  • 屬性縮寫{ name } 代替 { name: name }

  • 方法簡寫:省略 function 關鍵字

  • 計算屬性名稱:屬性名稱可動態生成


10. 可選串聯(Optional Chaining ?.

讓我們能安全存取深層屬性,而不會因 undefined 出錯。

:white_check_mark: 範例:

const user = { profile: { name: "Tom" } };
console.log(user.profile?.name); // "Tom"
console.log(user.address?.city); // undefined


11. 物件迭代方法

雖然物件不可直接迭代,但我們可以透過:

  • Object.keys() → 取得所有鍵

  • Object.values() → 取得所有值

  • Object.entries() → 取得 [鍵, 值] 陣列

:white_check_mark: 範例:

const obj = {a:1, b:2};
for (const [key, val] of Object.entries(obj)) {
  console.log(key, val);
}


:bullseye: 總結

現代 JavaScript 提供了豐富的語法:

  • 解構 → 簡化取值

  • Spread / Rest → 彈性操作資料

  • 邏輯/空值/賦值運算子 → 精簡邏輯判斷

  • 物件增強 & Optional Chaining → 讓物件處理更安全

這些特性結合起來,能讓程式碼更簡潔、易讀且強大。熟練這些技巧,我們就能寫出更現代化的 JavaScript! :rocket:


2個讚

現代 JavaScript 核心技巧:從解構到可選鏈接的完整指南

在現代 JavaScript(ES6+)中,有許多新特性幫助我們用更簡潔、可讀性更高的方式撰寫程式碼。本篇文章將帶你快速掌握以下幾個核心概念:

  • 解構(Destructuring)
  • 展開操作符(Spread Operator)
  • 其餘模式與參數(Rest Pattern and Parameters)
  • 短路求值(Short Circuiting)
  • 空值合併運算符(Nullish Coalescing Operator)
  • 邏輯賦值運算符(Logical Assignment Operators)
  • 增強型物件字面量(Enhanced Object Literals)
  • 可選鏈接(Optional Chaining)
  • 陣列與物件的循環(Looping Arrays and Objects)

1. 解構(Destructuring)

解構讓我們可以快速從 陣列或物件中取出值,並直接存入變數。

  • 陣列解構

    const arr = [1, 2, 3];
    const [a, , c] = arr;  
    console.log(a, c); // 1, 3
    

    :check_mark: 支援跳過元素、預設值、巢狀解構、函數多返回值。

  • 物件解構

    const user = { name: "Tom", age: 25 };
    const { name, age: years = 18 } = user;
    console.log(name, years); // Tom, 25
    

    :check_mark: 可以改變變數名稱、設預設值、處理巢狀物件。


2. 展開操作符(Spread Operator ...

展開操作符用於「展開」陣列或物件內容。

const arr1 = [1, 2];
const arr2 = [...arr1, 3, 4]; 
console.log(arr2); // [1, 2, 3, 4]

:check_mark: 用途:合併陣列、淺拷貝、傳遞多參數。
:check_mark: 物件也可用來拷貝或覆寫屬性。


3. 其餘模式與參數(Rest Pattern & Parameters)

與展開相反,「其餘」會把剩餘元素打包成一個集合。

const [head, ...rest] = [1, 2, 3, 4];
console.log(rest); // [2, 3, 4]

function sum(...nums) {
  return nums.reduce((a, b) => a + b, 0);
}
console.log(sum(1, 2, 3)); // 6

4. 短路求值(Short Circuiting)

邏輯運算子 ||&& 可以返回任何值,並具有短路特性。

console.log(0 || "default"); // "default"
console.log(5 && "yes");     // "yes"

:check_mark: 常用來設定預設值或簡化條件判斷。


5. 空值合併運算符(Nullish Coalescing ??

|| 類似,但只把 nullundefined 視為空值。

console.log(0 ?? 10);   // 0
console.log(null ?? 10); // 10

:check_mark: 適合處理 0 或空字串等「有效假值」。


6. 邏輯賦值運算符(Logical Assignment Operators)

ES2021 引入的語法糖:

let a = null;
a ??= 5; 
console.log(a); // 5

let b = "";
b ||= "fallback"; 
console.log(b); // "fallback"

:check_mark: 讓預設值處理更簡潔。


7. 增強型物件字面量(Enhanced Object Literals)

讓物件定義更直觀:

const age = 20;
const person = {
  age,                // 屬性縮寫
  greet() {           // 方法簡寫
    console.log("Hi!");
  },
  ["key" + 1]: "val", // 計算屬性名
};

8. 可選鏈接(Optional Chaining ?.

避免 undefined 錯誤的好幫手:

const user = {};
console.log(user.address?.city); // undefined

:check_mark: 經常與 ?? 搭配:

console.log(user.address?.city ?? "未知城市");

9. 陣列與物件循環(Looping)

  • for-of

    for (const val of [10, 20, 30]) {
      console.log(val);
    }
    
  • 物件循環

    for (const [k, v] of Object.entries({a:1, b:2})) {
      console.log(k, v);
    }
    

10. 實戰:足球遊戲應用挑戰

這些技巧能應用在小專案裡,例如足球比賽遊戲模擬:

  • 用解構拆分球員名單
  • 用展開合併陣列
  • 用其餘參數處理不限數量的得分者
  • 用短路求值簡化條件判斷
  • 用可選鏈接與空值合併處理缺失資料

結語

這些 ES6+ 的特性,讓我們在處理資料結構時更直觀、更安全,並且能寫出更簡潔的程式碼。建議在實作中反覆練習,並將它們靈活應用到日常專案裡。


2個讚