跳至主要内容

9 篇文章 含有標籤「JavaScript」

檢視所有標籤

AOS(Animate On Scroll Library)入門教學筆記 | 學習筆記

· 閱讀時間約 5 分鐘
kdchang

在現代網頁設計中,視覺效果和互動性已經成為提升使用者體驗的重要元素。當使用者向下滾動頁面時,如果某些區塊能夠平滑地出現、滑入、淡入或放大,能大大提升網站的專業感和吸引力。這類效果通常被稱為「滾動動畫」。

AOS (Animate On Scroll) 是一個輕量級的 JavaScript 函式庫,讓你可以輕鬆地為 HTML 元素加上動畫效果,並且在元素進入畫面時自動播放動畫。它不需要你手動寫 JavaScript 控制事件,也不依賴大型框架,學習曲線平緩,非常適合想快速加上動畫效果的開發者。


一、AOS 的特點

  • 輕量:只有數十 KB,對效能影響小。
  • 易於使用:只需要加幾個 data-aos 屬性在 HTML 元素上即可。
  • 可自訂動畫:支援動畫類型、延遲時間、持續時間、執行次數等調整。
  • 無框架依賴:可搭配純 HTML/CSS/JS 使用,也支援 React、Vue 等框架。
  • 良好的瀏覽器支援:支援所有現代瀏覽器。

二、如何安裝 AOS

方法一:使用 CDN(最簡單方式)

在你的 HTML 檔案 <head> 加入 CSS:

<link href="https://unpkg.com/aos@2.3.4/dist/aos.css" rel="stylesheet">

<body> 結尾加入 JS:

<script src="https://unpkg.com/aos@2.3.4/dist/aos.js"></script>
<script>
AOS.init();
</script>

方法二:透過 npm 安裝(建議在模組化專案中使用)

npm install aos --save

在你的 JavaScript 中引入與初始化:

import AOS from 'aos';
import 'aos/dist/aos.css';

AOS.init();

三、基本用法

只要在 HTML 元素上加入 data-aos 屬性即可。例如:

<div data-aos="fade-up">
這段文字將會在滾動時從下方淡入出現
</div>

常見的動畫效果:

效果名稱說明
fade淡入
fade-up向上淡入
fade-down向下淡入
fade-left向左淡入
fade-right向右淡入
zoom-in放大淡入
zoom-out縮小淡入
flip-left向左翻轉進場
slide-up向上滑入
slide-down向下滑入

四、進階設定

AOS 提供許多自訂參數,以下為常用屬性說明:

1. data-aos-duration

動畫持續時間(毫秒),預設為 400ms:

<div data-aos="fade-up" data-aos-duration="1000">
動畫持續 1 秒
</div>

2. data-aos-delay

動畫延遲時間(毫秒),可用來讓多個元素依序出現:

<div data-aos="fade-up" data-aos-delay="0">第一個</div>
<div data-aos="fade-up" data-aos-delay="200">第二個</div>
<div data-aos="fade-up" data-aos-delay="400">第三個</div>

3. data-aos-once

設定是否只執行一次動畫(預設為 false,表示每次滾動進入都會重新動畫):

<div data-aos="fade-up" data-aos-once="true">
只播放一次動畫
</div>

4. data-aos-offset

控制動畫啟動前的滾動距離(單位:像素):

<div data-aos="fade-up" data-aos-offset="300">
滾動到距離螢幕頂端 300px 時才開始動畫
</div>

五、實際範例

以下是一個完整的簡單 HTML 範例:

<!DOCTYPE html>
<html lang="zh-Hant">
<head>
<meta charset="UTF-8">
<title>AOS 教學範例</title>
<link href="https://unpkg.com/aos@2.3.4/dist/aos.css" rel="stylesheet">
<style>
body {
font-family: sans-serif;
padding: 0;
margin: 0;
}
section {
height: 100vh;
display: flex;
align-items: center;
justify-content: center;
font-size: 2rem;
border-bottom: 1px solid #ccc;
}
</style>
</head>
<body>

<section>
<div data-aos="fade-up">第一個區塊</div>
</section>

<section>
<div data-aos="zoom-in" data-aos-delay="200">第二個區塊</div>
</section>

<section>
<div data-aos="slide-left" data-aos-duration="800">第三個區塊</div>
</section>

<script src="https://unpkg.com/aos@2.3.4/dist/aos.js"></script>
<script>
AOS.init();
</script>

</body>
</html>

你可以將這段程式碼儲存為 HTML 檔案後,直接打開瀏覽器觀看滾動動畫效果。


六、常見問題與注意事項

  1. AOS 沒有效果?
    確認你有正確載入 aos.css 和執行 AOS.init()

  2. 元素進入畫面但沒有動畫?
    嘗試調整 data-aos-offset 或確認元素是否真的進入視窗中。

  3. 動畫無法重複?
    預設會重複,除非你加上了 data-aos-once="true"

  4. 與 SPA 框架(如 React、Vue)整合時動畫失效?
    動態渲染的頁面需在 DOM 更新完後重新執行 AOS.refresh()


總結

AOS 是一個非常實用又容易上手的前端動畫工具。你不需要寫複雜的 JavaScript,只要加幾行 data-aos 屬性就能為你的網站加入吸引人的動態效果。無論是製作個人作品集、商業網站或展示頁面,AOS 都是快速提升視覺層次感的絕佳利器。

當你需要更細緻的動畫控制或複雜的交互邏輯,也可以進一步探索 GSAPScrollMagic 等更強大的動畫工具。但若只是想快速達到流暢的滾動動畫,AOS 絕對是一個值得推薦的選擇。

參考文件

  1. gsap
  2. scrollmagic

Lodash 介紹與入門教學筆記 | 學習筆記

· 閱讀時間約 3 分鐘
kdchang

前言

在 JavaScript 的開發中,資料處理與函式操作經常需要處理陣列、物件、字串的轉換、搜尋與過濾等需求。儘管 ES6+ 提供了不少內建函式(如 mapfilterreduce 等),但仍有許多情境需要進階或更簡潔的處理方式。

這時候,Lodash 就是一個非常實用的工具庫。它是一個提供大量實用函式的 JavaScript 函式庫,能幫助開發者更方便地進行資料操作、提升開發效率與可讀性。


重點摘要

  • Lodash 是什麼:

    • 一個現代 JavaScript 實用工具庫,專注於資料處理、陣列與物件操作。
    • 模組化設計,可依照需求引入特定函式,減少最終 bundle 大小。
  • 使用方式:

    • 安裝方式:

      npm install lodash
    • 引入方式(使用 ES6 模組):

      import _ from 'lodash';
  • 常用函式分類:

    • 陣列操作:chunkcompactdifferenceuniqflatten
    • 物件操作:getsetmergepickomit
    • 函式處理:debouncethrottleonce
    • 數學與邏輯判斷:isEmptyisEqualclamp
    • 字串操作:camelCasekebabCasestartCase
  • 優點:

    • API 設計一致,學習曲線平緩
    • 可與原生 JS 無縫搭配
    • 處理巢狀資料與深層結構特別方便

實際範例

以下透過幾個實際範例來展示 Lodash 的常見使用情境與語法。

1. 陣列切分:_.chunk

將一個陣列依照固定大小切成多個子陣列。

import _ from 'lodash';

const arr = [1, 2, 3, 4, 5, 6];
const result = _.chunk(arr, 2);
// 輸出:[[1, 2], [3, 4], [5, 6]]

2. 去除 falsy 值:_.compact

移除陣列中的 falsenull0""undefinedNaN

const arr = [0, 1, false, 2, '', 3];
const result = _.compact(arr);
// 輸出:[1, 2, 3]

3. 陣列差集:_.difference

找出第一個陣列中,不存在於其他陣列的元素。

const result = _.difference([1, 2, 3, 4], [2, 3]);
// 輸出:[1, 4]

4. 去除重複值:_.uniq

回傳一個不含重複值的新陣列。

const result = _.uniq([2, 1, 2]);
// 輸出:[2, 1]

5. 平坦化陣列:_.flatten

將多維陣列的一層扁平化。

const result = _.flatten([1, [2, [3, [4]]]]);
// 輸出:[1, 2, [3, [4]]]

若要完全扁平化,可使用 flattenDeep

const result = _.flattenDeep([1, [2, [3, [4]]]]);
// 輸出:[1, 2, 3, 4]

6. 取得物件巢狀值:_.get

避免使用多層 obj && obj.prop 判斷。

const obj = { a: { b: { c: 42 } } };
const result = _.get(obj, 'a.b.c');
// 輸出:42

可設定預設值:

const result = _.get(obj, 'a.b.d', 'not found');
// 輸出:'not found'

7. 防抖動(Debounce):_.debounce

常用於輸入框搜尋防抖,例如搜尋建議:

const search = _.debounce((query) => {
console.log('搜尋中:', query);
}, 300);

search('a');
search('ab');
search('abc'); // 只會觸發這次

8. 函式執行一次:_.once

保證某個函式只執行一次。

const init = _.once(() => {
console.log('只會執行一次的初始化');
});

init();
init();
// 輸出:只會執行一次的初始化

總結

Lodash 是一個穩定、完整、社群活躍的 JavaScript 工具函式庫,適合用於各種日常資料處理場景。尤其當面對資料轉換、巢狀結構處理、函式優化(如 debounce/throttle)等問題時,Lodash 提供了直觀且一致的解法。

若在專案中引入 Lodash 時,建議採用模組化方式僅引入需要的函式,或使用 lodash-es(es module 版本) 搭配 Tree Shaking,以減少最終輸出大小。

JavaScript this 使用情境入門教學筆記 | 學習筆記

· 閱讀時間約 3 分鐘
kdchang

在 JavaScript 中,箭頭函式(arrow function)與傳統函式在 this 的行為上有一些不同。箭頭函式不會創建自己的 this,而是繼承外部作用域的 this,這就是為什麼你會遇到 this 的問題。

傳統函式中的 this

在傳統的函式中,this 會指向該函式被調用時的上下文。例如,當函式作為事件處理器時,this 會指向觸發事件的元素。

function regularFunction() {
console.log(this); // 'this' 是調用它的上下文
}

const obj = {
name: 'KD',
show: regularFunction
};

obj.show(); // 'this' 會指向 obj

箭頭函式中的 this

在箭頭函式中,this 並不會綁定到函式的上下文,而是繼承自外部作用域。這通常會讓箭頭函式的 this 變得不同於你預期的結果。

例子:this 的問題

假設有這樣的情境,當你在一個物件的方法中使用箭頭函式作為事件處理器,this 會指向外部作用域,而不是該物件本身。

const obj = {
name: 'KD',
show: function() {
// 使用傳統函式作為事件處理器
document.getElementById('btn').addEventListener('click', function() {
console.log(this); // 'this' 指向的是 'btn' 按鈕元素
});

// 使用箭頭函式作為事件處理器
document.getElementById('btn').addEventListener('click', () => {
console.log(this); // 'this' 指向外部作用域,即 'obj' 物件
});
}
};

obj.show();
  • 在傳統函式中,this 會指向觸發事件的 DOM 元素(這裡是 btn 按鈕)。
  • 在箭頭函式中,this 會指向外部作用域(這裡是 obj 物件),因為箭頭函式不會創建自己的 this

解決方案:確保 this 正確指向

如果你希望 this 指向物件本身,可以使用傳統函式或手動綁定 this

使用傳統函式

如果你希望在事件處理器中讓 this 指向物件本身,可以使用傳統函式,或者使用 bind 顯式綁定 this

const obj = {
name: 'KD',
show: function() {
document.getElementById('btn').addEventListener('click', function() {
console.log(this); // 'this' 指向 obj
}.bind(this)); // 顯式綁定 'this' 到 obj
}
};

obj.show();

另一個選項:箭頭函式和外部 this

如果你希望繼續使用箭頭函式,你可以將物件的 this 儲存到外部變數中,並在箭頭函式中引用它。

const obj = {
name: 'KD',
show: function() {
const self = this; // 保存物件的 'this'
document.getElementById('btn').addEventListener('click', () => {
console.log(self); // 使用外部的 'self',指向 obj
});
}
};

obj.show();

總結

  • 傳統函式 會根據調用上下文決定 this 的值。
  • 箭頭函式 會繼承外部作用域的 this,不會創建自己的 this,這樣在某些情況下會導致 this 不如預期。
  • 如果你需要在事件處理器中使用物件的 this,可以選擇使用傳統函式或顯式綁定 this

JavaScript 多事件處理綁定使用情境入門教學筆記 | 學習筆記

· 閱讀時間約 3 分鐘
kdchang

在 JavaScript 中,你可以通過事件處理的方式來為多個 input 元素綁定事件處理器。這樣做可以讓你在父容器上綁定一個事件處理器,並通過 event.target 確定觸發事件的具體 input 元素,而不需要為每個 input 元素單獨綁定事件。

事件委派的概念

事件委派是一種常見的事件處理技術,它將事件綁定到父元素或容器上,然後通過 event.target 來確定哪個子元素觸發了事件。這種方式在動態生成的元素中非常有用,因為無論多少個元素,它們都會使用相同的事件處理器。

例子:為多個 input 元素使用事件委派

假設有多個 input 元素,並且我們希望根據用戶在每個 input 中的輸入執行某些操作,可以像這樣使用 event.target

<div id="inputContainer">
<input type="text" id="input1" />
<input type="text" id="input2" />
<input type="text" id="input3" />
</div>

<script>
// 綁定事件處理器到父容器
document.getElementById('inputContainer').addEventListener('input', function(event) {
// 檢查事件目標是否為 input 元素
if (event.target.tagName.toLowerCase() === 'input') {
console.log('觸發的 input 元素 ID:', event.target.id);
console.log('輸入的值:', event.target.value);
}
});
</script>

解釋:

  1. 我們將 input 元素的 input 事件綁定到父容器 #inputContainer 上。
  2. 當任何一個 input 元素觸發 input 事件時,事件會冒泡到父容器,並且事件處理器會被執行。
  3. 在事件處理器中,我們使用 event.target 來確定是哪個 input 元素觸發了事件。event.target 會返回實際觸發事件的元素。
  4. 通過 event.target.idevent.target.value,我們可以獲取觸發事件的 input 元素的 ID 和輸入的值。

優點:

  • 減少事件綁定數量:不需要為每個 input 元素單獨綁定事件,減少了冗餘代碼。
  • 動態元素支持:即使後來添加了新的 input 元素,父容器上的事件處理器也會自動處理新元素。

input 元素是動態創建時:

如果你有動態創建的 input 元素,事件委派依然有效,因為事件處理器是綁定在父容器上的,而不需要直接綁定在每個 input 元素上。

// 假設需要動態創建 input 元素
const container = document.getElementById('inputContainer');

for (let i = 1; i <= 5; i++) {
const input = document.createElement('input');
input.type = 'text';
input.id = 'input' + i;
container.appendChild(input);
}

這樣,當你動態創建新的 input 元素時,父容器上的事件處理器會自動處理這些新的 input 元素。

Vue pinia 保持 reactive 入門教學筆記 | 學習筆記

· 閱讀時間約 2 分鐘
kdchang

保持 reactive 寫法:


1️. 用 computed

const todos = computed(() => todoStore.todos)

優點

  • 保持 reactive
  • 簡單直接
  • 在 template 裡 todos 可以直接使用

缺點

  • 如果只是讀值,其實有點多餘

建議用於:在 template 需要用 v-for="todo in todos" 這種情況下。


2️. 直接使用 todoStore.todos 在 template

不額外宣告變數,直接寫:

<ul>
<li v-for="todo in todoStore.todos" :key="todo.id">
{{ todo.text }}
</li>
</ul>

優點

  • 直接讀取 store,最簡單
  • 不需要 computed

缺點

  • 如果在 script 多處使用 todos,每次都要寫 todoStore.todos

建議用於:只在 template 需要使用 todos 的情況。


3️. 使用 storeToRefs

這是 Pinia 官方推薦的方式,可以一次把 state 解構成 reactive ref:

import { storeToRefs } from 'pinia'

const todoStore = useTodoStore()
const { todos } = storeToRefs(todoStore)

優點

  • todos 是 reactive
  • 取值時不會失去 reactive
  • 適合同時取多個 state(例如 const { todos, count } = storeToRefs(todoStore)

缺點

  • 需要額外 import storeToRefs
  • 初學者可能不熟悉

建議用於:component 中需要多個 state 且偏好解構寫法時。


寫法比較

寫法是否 reactive適用場景
computed 包一層script 內多次使用
直接 todoStore.todos只在 template 使用
storeToRefs多個 state 解構需要時

建議

  • 如果只需要一個 state:computed 或直接用 todoStore.todos
  • 如果需要多個 state:storeToRefs

範例(使用 storeToRefs

<script setup>
import { useTodoStore } from '../stores/todoStore'
import { storeToRefs } from 'pinia'

const todoStore = useTodoStore()
const { todos } = storeToRefs(todoStore)

function addTodo() { ... }
function removeTodo(id) { ... }
function toggleComplete(id) { ... }
</script>

template 裡直接使用 todos,效果與 computed 相同。


總結
三種寫法都可行,主要差異在語法風格與使用場景。若不想意外解構成非 reactive 值,使用 storeToRefs 是最安全的。

JavaScript Hoisting 入門教學筆記 | 學習筆記

· 閱讀時間約 4 分鐘
kdchang

1. 什麼是 Hoisting?

Hoisting(提升)是 JavaScript 中的一種行為,它允許變數與函式在執行時被提升到作用域的頂部,這表示你可以在宣告之前使用它們,而不會發生錯誤。「建立期」(Creation Phase)和「執行期」(Execution Phase),建立期主要為定義變數名稱,執行期為執行程式和指定賦值。

在 JavaScript 中,Hoisting 影響兩種類型的宣告:

  1. 變數宣告(var, let, const)
  2. 函式宣告(Function Declaration)

2. 變數 Hoisting

2.1 使用 var 的 Hoisting

var 宣告的變數會被提升,但不會初始化,這表示變數本身會被提升到作用域頂端,但其值不會。

console.log(a); // undefined
var a = 10;
console.log(a); // 10

上述程式碼等同於:

var a;
console.log(a); // undefined

a = 10;
console.log(a); // 10

在 Hoisting 過程中,變數 a 被提升(Hoist)到了作用域的頂部,但它的值 10 並沒有一起提升,因此第一次 console.log(a); 會輸出 undefined

2.2 使用 letconst 的 Hoisting

letconst 也會被提升,但它們不會自動初始化,因此在變數宣告之前存取會導致 ReferenceError

console.log(b); // ReferenceError: Cannot access 'b' before initialization
let b = 20;

等同於:

let b;
console.log(b); // ReferenceError
b = 20;

letconst 變數存在「暫時性死區(Temporal Dead Zone, TDZ)」,這表示變數在初始化之前無法被存取。

console.log(c); // ReferenceError
const c = 30;

2.3 總結變數 Hoisting

宣告方式是否 Hoisting是否初始化TDZ 存在
varundefined
let
const

3. 函式 Hoisting

3.1 Function Declaration(函式宣告)

函式宣告(function foo() {})會完整 Hoisting,因此可以在定義之前調用。

hello(); // Hello, world!

function hello() {
console.log("Hello, world!");
}

在執行時,JavaScript 會將函式整個提升到作用域頂部,因此 hello() 可以在函式宣告前執行。

等同於:

function hello() {
console.log("Hello, world!");
}

hello(); // Hello, world!

3.2 Function Expression(函式表達式)

使用 var 宣告的函式表達式(Function Expression)僅會提升變數,但不會提升函式內容,因此無法在宣告前調用。

console.log(sayHi); // undefined
sayHi(); // TypeError: sayHi is not a function

var sayHi = function() {
console.log("Hi!");
};

上述程式碼等同於:

var sayHi;
console.log(sayHi); // undefined

sayHi = function() {
console.log("Hi!");
};

因為 sayHi 在 Hoisting 時只被提升變數,但未初始化,因此 console.log(sayHi); 顯示 undefined,並且 sayHi(); 會導致 TypeError

3.3 使用 letconst 的 Function Expression

若函式表達式使用 letconst,則變數仍然會被提升,但會受到暫時性死區(TDZ)影響,因此在初始化前使用會導致 ReferenceError

console.log(sayHello); // ReferenceError: Cannot access 'sayHello' before initialization
let sayHello = function() {
console.log("Hello!");
};

4. 結論與最佳實踐

4.1 總結 Hoisting 行為

  1. 變數宣告
    • var 會被提升並初始化為 undefined
    • letconst 會被提升,但不會初始化(存在 TDZ)。
  2. 函式宣告
    • function 會完整提升,可以在宣告前調用。
    • var 宣告的函式表達式只提升變數,無法在宣告前調用。
    • letconst 宣告的函式表達式受 TDZ 影響,無法在宣告前使用。

4.2 最佳實踐

  • 避免使用 var,改用 letconst
  • 函式表達式應在使用前宣告,避免 undefinedReferenceError
  • 將所有變數與函式宣告放在作用域的開頭,可減少 Hoisting 帶來的困惑。

4.3 最佳實踐範例

// 正確做法:將變數與函式宣告放在最上方
function greet() {
console.log("Hello, world!");
}

greet();

const sayHi = function() {
console.log("Hi!");
};

sayHi();

這樣可以確保程式碼易於理解,並避免因 Hoisting 造成的問題。

參考文件

  1. [JavaScript] Javascript 的執行環境 (Execution context) 與堆疊 (Stack)
  2. 初學者指南:深入了解 JavaScript 中的 Event Loop(事件循環)
  3. 初學者指南:深入了解 JavaScript 的 Call Stack(呼叫堆疊)
  4. 初學者指南:深入了解 JavaScript 的執行環境(Execution Context)
  5. 初學者指南:深入了解 JavaScript 的建立期與執行期
  6. 初學者指南:深入了解 JavaScript 中函式與變數的建立期與執行期差異

JavaScript 入門教學筆記 | 學習筆記

· 閱讀時間約 4 分鐘
kdchang

前言

JavaScript(簡稱 JS)是一種高階、直譯式、弱型別的程式語言,廣泛應用於 Web 開發。它最初用於瀏覽器端,現在也能在伺服器端(如 Node.js)運行,並支援多種應用開發,如網頁、行動應用、桌面應用等。


1. JavaScript 的基本語法

1.1 變數與常數

在 JavaScript 中,可以使用 varletconst 來宣告變數。

var a = 10; // 傳統變數宣告(不建議使用)
let b = 20; // 可變變數
const c = 30; // 常數,無法重新賦值

letconst 具有區塊作用域(Block Scope),而 var 則具有函式作用域(Function Scope)。


1.2 資料型別

JavaScript 主要的資料型別包括:

  • 原始型別(Primitive Types)

    • string(字串)
    • number(數字,包括整數與浮點數)
    • boolean(布林值)
    • null(空值)
    • undefined(未定義)
    • symbol(符號,ES6 引入)
  • 參考型別(Reference Types)

    • object(物件)
    • array(陣列)
    • function(函式)

範例:

let name = 'Alice'; // 字串
let age = 25; // 數字
let isStudent = true; // 布林值
let hobby = null; // 空值
let score; // 未定義(undefined)
let person = { name: 'Bob', age: 30 }; // 物件
let colors = ['red', 'green', 'blue']; // 陣列

2. 運算子

2.1 算術運算子

let x = 10;
let y = 5;

console.log(x + y); // 加法:15
console.log(x - y); // 減法:5
console.log(x * y); // 乘法:50
console.log(x / y); // 除法:2
console.log(x % y); // 餘數:0
console.log(x ** 2); // 次方運算:100

2.2 比較運算子

console.log(10 > 5); // true
console.log(10 >= 10); // true
console.log(10 < 5); // false
console.log(10 === '10'); // false(全等)
console.log(10 == '10'); // true(寬鬆比較)
console.log(10 !== '10'); // true(全不等)
console.log(10 != '10'); // false(寬鬆不等)

2.3 邏輯運算子

console.log(true && false); // false(AND)
console.log(true || false); // true(OR)
console.log(!true); // false(NOT)

3. 控制流程

3.1 條件判斷

let score = 75;

if (score >= 90) {
console.log('A');
} else if (score >= 80) {
console.log('B');
} else {
console.log('C');
}

3.2 三元運算子

let age = 18;
let canVote = age >= 18 ? '可以投票' : '不可以投票';
console.log(canVote);

3.3 switch 語法

let fruit = 'apple';

switch (fruit) {
case 'banana':
console.log('黃色');
break;
case 'apple':
console.log('紅色');
break;
default:
console.log('未知');
}

4. 迴圈

4.1 for 迴圈

for (let i = 1; i <= 5; i++) {
console.log('數字:' + i);
}

4.2 while 迴圈

let num = 1;

while (num <= 5) {
console.log('數字:' + num);
num++;
}

4.3 forEach(適用於陣列)

let colors = ['red', 'green', 'blue'];

colors.forEach(function (color) {
console.log(color);
});

5. 函式(Functions)

5.1 一般函式

function add(a, b) {
return a + b;
}

console.log(add(3, 5)); // 8

5.2 箭頭函式(Arrow Function)

const multiply = (a, b) => a * b;

console.log(multiply(4, 6)); // 24

5.3 立即執行函式(IIFE)

(function () {
console.log('這是立即執行函式');
})();

6. 陣列與物件

6.1 陣列操作

let fruits = ['apple', 'banana', 'cherry'];

fruits.push('grape'); // 新增
console.log(fruits); // ['apple', 'banana', 'cherry', 'grape']

fruits.pop(); // 移除最後一個
console.log(fruits); // ['apple', 'banana', 'cherry']

6.2 物件操作

let person = {
name: 'Alice',
age: 25,
greet: function () {
console.log('Hello, my name is ' + this.name);
}
};

console.log(person.name); // 'Alice'
person.greet(); // 'Hello, my name is Alice'

7. 非同步處理

7.1 setTimeoutsetInterval

setTimeout(() => {
console.log('這段文字將在 2 秒後出現');
}, 2000);

7.2 Promise

let fetchData = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('資料已載入');
}, 2000);
});

fetchData.then((message) => console.log(message));

7.3 async/await

async function fetchData() {
return '資料已載入';
}

fetchData().then(console.log);

總結

JavaScript 是一種靈活且功能強大的語言,適用於前端與後端開發。本文介紹了基本語法、變數、運算子、控制流程、函式、陣列、物件及非同步處理等內容,這些知識構成 JavaScript 入門的基礎。建議透過實際練習來加深理解,如使用瀏覽器開發者工具或建立小型專案來測試所學內容。

JavaScript 練習挑戰紀錄 | 學習筆記

· 閱讀時間約 4 分鐘
kdchang

Longest Word

當我們執行 paragraph.match(/[a-z]+/gi) 時,這段 JavaScript 程式碼的意思是:

目的:

paragraph 字串中找出所有連續的英文字母(不分大小寫)組成的片段,並以陣列形式回傳。


語法拆解:

paragraph.match(/[a-z]+/gi)
部分意思
paragraph要處理的字串(變數名)
.match(...)是一個字串的方法,會根據正則表達式去尋找所有符合條件的子字串
/[a-z]+/gi正則表達式:搜尋一或多個英文字母
[a-z]表示小寫英文字母 a 到 z(大寫會由 i 修飾符處理)
+表示「一個或多個」符合前面 [a-z] 的字元
gglobal 全域搜尋,找到所有符合條件的片段
iignore case 忽略大小寫,讓 [a-z] 同時能配對 A-Z

範例:

const paragraph = "Hello, 世界! This is a test123.";
const result = paragraph.match(/[a-z]+/gi);
console.log(result);

輸出:

["Hello", "This", "is", "a", "test"]

這段程式會:

  • 忽略中文與數字
  • 把英文字母串(不論大小寫)全都抓出來

好,我們真的慢慢來,我會用超直白的說法、一步一步演示,幫你理解 arr.sort((a, b) => a - b) 是怎麼把數字從小排到大的。


先記住一個核心概念:

arr.sort((a, b) => a - b);

這一行的意思是:

陣列裡的「每兩個數字 a 和 b」,如果 a 比 b 小,就讓 a 排在 b 前面。


一步一步來看:

假設這個陣列:

let arr = [30, 10, 5];

我們要用 sort() 排成:

[5, 10, 30]

JS 怎麼做的?

它會自動幫你「兩個兩個配對」來比較順序。

第一次比較:30 和 10

a = 30, b = 10
a - b = 30 - 10 = 20(是正數)

JavaScript 覺得:b(10)比較小 → 讓 10 排在 30 前面

結果變成這樣:

[10, 30, 5]

第二次比較:30 和 5

a = 30, b = 5
a - b = 30 - 5 = 25(是正數)

b(5)比較小 → 把 5 放到前面

結果變成:

[10, 5, 30]

第三次比較:10 和 5

a = 10, b = 5
a - b = 10 - 5 = 5(是正數)

b(5)比較小 → 把 5 放到前面

最後得到:

[5, 10, 30]

就是我們想要的「從小到大」排序!


最簡單的記法:

語法排序方式
(a, b) => a - b小到大
(a, b) => b - a大到小

小挑戰

let arr = [8, 3, 100, 1];
arr.sort((a, b) => a - b); // [1, 3, 8, 100]

Codeland Username Validation

符合條件的正則表達式:

正則表達式:

^[A-Za-z][A-Za-z0-9_]{2,23}[A-Za-z0-9]$

解釋:

  1. ^:字串的開始。
  2. [A-Za-z]:第一個字符必須是字母(無論是大寫還是小寫)。
  3. [A-Za-z0-9_]{2,23}:接下來可以包含字母、數字或底線,並且長度必須在 2 到 23 之間。這確保了整個字串的長度在 4 到 25 之間(包括起始的字母)。
  4. [A-Za-z0-9]:字串的結尾必須是字母或數字,不能是底線 _
  5. $:字串的結束。

規則解釋:

  1. 用戶名必須是 4 到 25 個字符。
  2. 用戶名的開頭必須是字母。
  3. 用戶名可以包含字母、數字和底線 _
  4. 用戶名不能以底線 _ 結尾。

範例:

  • "username123" 會匹配成功。
  • "user_name" 會匹配成功。
  • "user_name_" 會匹配失敗(因為底線 _ 在結尾)。
  • "123username" 會匹配失敗(因為開頭不是字母)。
  • "user" 會匹配成功。
  • "a_1" 會匹配失敗(因為長度太短,少於 4 個字符)。

2620. Counter

var createCounter = function(n) {
return function() {
return n++;
};
};

這樣做的好處是:

n 是外部函式的區域變數(closure

每次呼叫內部函式都能使用並修改 n

n++ 會先回傳 n 的值,再讓 n 加 1

小補充:n++ vs ++n n++:先回傳,再加一 ++n:先加一,再回傳