# 📘 Document
`document` 是 DOM 操作的入口,在純 JavaScript 裡操作 HTML 的核心物件。除了 `querySelector` 與 `createElement`,以下是**最常用也最實用的 `document` 方法與屬性**,我依照用途幫你分類:
---
## 🔍 元素選取(DOM 查詢)
| 方法 | 說明 |
| ----------------------------------- | --------------------------------- |
| `getElementById(id)` | 用 `id` 取得單一元素(老方法,但仍實用) |
| `getElementsByClassName(className)` | 取得有指定 class 的所有元素(HTMLCollection) |
| `getElementsByTagName(tagName)` | 取得指定 tag 的所有元素(HTMLCollection) |
| `querySelector(selector)` | 取得符合 CSS 選擇器的**第一個**元素 |
| `querySelectorAll(selector)` | 取得所有符合的元素(NodeList) |
---
## 🧱 元素建立與節點操作
| 方法/屬性 | 說明 |
| ---------------------------------------------- | ---------------------------------------- |
| `createElement(tag)` | 建立新元素,例如 `document.createElement('div')` |
| `createTextNode(text)` | 建立文字節點(用於插入純文字) |
| `importNode(node, deep)` | 匯入其他 document 的節點 |
| `fragment = document.createDocumentFragment()` | 建立「虛擬 DOM」暫存節點,效率高於直接插入 |
| `document.body`, `document.head` | 直接取 `<body>` 或 `<head>` 節點 |
| `document.documentElement` | 取得 `<html>` 根節點 |
---
## 📄 文件與事件資訊
| 屬性/方法 | 說明 |
| ------------------------------------- | -------------------------------------- |
| `document.title` | 網頁標題,可讀可寫 |
| `document.URL` | 當前網址(唯讀) |
| `document.readyState` | 加載狀態(loading / interactive / complete) |
| `document.addEventListener(type, fn)` | 加事件監聽,像 `DOMContentLoaded` |
| `document.removeEventListener(...)` | 移除事件監聽 |
---
## 📋 複製/剪貼簿(Clipboard)
| 方法 | 說明 |
| ------------------------------------- | ----------------------------- |
| `execCommand('copy')` *(舊)* | 嘗試觸發複製(已過時,建議用 Clipboard API) |
| `navigator.clipboard.readText()` | 讀取剪貼簿內容(async) |
| `navigator.clipboard.writeText(text)` | 將文字寫入剪貼簿 |
---
## 🧪 其它有用方法
| 方法/屬性 | 說明 |
| ----------------------------------------------- | ------------------ |
| `element.contains(child)` | 判斷某元素是否包含另一元素 |
| `element.cloneNode(deep)` | 複製節點(`true`=含子孫) |
| `element.remove()` | 從 DOM 移除元素 |
| `element.append(...)` / `prepend(...)` | 插入元素或文字(可多個) |
| `element.innerHTML`, `textContent`, `outerHTML` | 操作 HTML/純文字/整個元素字串 |
---
## 🧠 小提醒:DOM 節點操作也很多是在 `element` 上
例如:
```js
const div = document.createElement('div');
div.classList.add('box');
div.textContent = 'Hello';
document.body.appendChild(div);
```
這些像 `classList`, `textContent`, `appendChild`, `removeChild` 都是在元素物件上(非 `document` 本身)。
### 使用 `insertAdjacentElement` 將元件串接在後
```js
const btn3 = document.getElementById('myBtn');
const newBtn3 = document.createElement('button');
newBtn3.id = 'newBtn3';
newBtn3.textContent = '新增按鈕 C';
// 直接把 newBtn3 插到 btn3 旁邊(afterend)
btn3.insertAdjacentElement('afterend', newBtn3);
```
---
---
# 📘 Regex
```js
// 將 "world" 替換為 "universe"
var str = "Hello, world!";
var newStr = str.replace(/world/, "universe"); // 使用正則表達式進行替換
console.log(newStr); // "Hello, universe!"
// 替換所有數字為 "#"
var text = "12345 and 67890";
var replacedText = text.replace(/\d/g, "#");
console.log(replacedText); // "##### and #####"
// 將 yyyy-mm-dd 格式的日期轉換成 mm/dd/yyyy 格式
var dateStr = "2023-05-25";
var formattedDate = dateStr.replace(/(\d{4})-(\d{2})-(\d{2})/, "$2/$3/$1");
console.log(formattedDate); // "05/25/2023"
// 首字字母大寫,其餘小寫
function format(str) {
return str.toLowerCase().replace(/^\w/, (c) => c.toUpperCase());
}
```
在 JavaScript(以下簡稱 “JS”)裡,正則表示式(RegExp)主要有兩種宣告方式,並搭配一系列常用的標誌(flag)與語法結構。以下分段說明並輔以範例。
一、宣告方式
1. 文字(Literal)語法
let re = /pattern/flags;
範例:
```js
const re1 = /\d{3}-\d{4}/g; // 尋找「3 位數字 + ‘-’ + 4 位數字」,全域搜尋
```
2. 建構子(Constructor)語法
let re = new RegExp("pattern", "flags");
範例:
```js
const re2 = new RegExp("\\d{3}-\\d{4}", "g");
// 在字串中,\ 要再多加一層跳脫
```
二、常用標誌(Flags)
- g (global):全域搜尋,不只第一筆
- i (ignore case):不分大小寫
- m (multiline):多行模式,^、$ 可在每行起/尾匹配
- u (unicode):啟用 Unicode 支援(例如 u+{1F601})
- s (dotAll):讓 . 能匹配換行符(\n)
- y (sticky):「黏貼」模式,從 lastIndex 精確位置開始匹配
三、核心語法元件與範例
1. 字元類別(Character Classes)
- \d:數字等價於 [0-9]
- \D:非數字等價於 [^0-9]
- \w:英文數字底線 [A-Za-z0-9_]
- \W:非 \w
- \s:空白字元 [\t\n\r\f\v]
- . :除換行以外的任意字元(s 標誌下可包含換行)
範例:
```js
/\w+@\w+\.\w{2,3}/i // 電子郵件簡易匹配
```
2. 量詞(Quantifiers)
- X*:0 次或多次
- X+:1 次或多次
- X?:0 次或 1 次
- X{n}:剛好 n 次
- X{n,}:至少 n 次
- X{n,m}:介於 n–m 次
範例:
```js
/a{2,4}/ // "aa", "aaa", "aaaa" 都可
```
3. 邊界與定位符(Anchors)
- ^:字串或行首
- $:字串或行尾
- \b:單字邊界
- \B:非單字邊界
範例:
```js
/^Hello/ // 以 Hello 開頭
/world!$/ // 以 world! 結尾
/\bcat\b/ // 獨立的 "cat"
```
4. 群組與選擇
- ( … ):括號群組,默認會記錄(capturing group)
- (?: … ):非記錄群組(non-capturing)
- |:或(alternation)
範例:
```js
/(dog|cat)s?/ // dog, dogs, cat, cats
/(?:Mr|Mrs)\.?\s[A-Z][a-z]+/ // 非捕獲:Mr. Smith, Mrs Jones
```
5. 前瞻與後顧(Lookaround)
- (?= … ):正向前瞻
- (?! … ):負向前瞻
- (?<= … ):正向後顧 (ES2018+)
- (?<! … ):負向後顧 (ES2018+)
範例:
```js
/\d+(?=%)/ // 匹配緊跟百分比符號前的數字
/(?<=\$)\d+/ // 匹配美元符號後的數字
```
四、常用搭配方法
1. RegExp 物件方法
- test(str):回傳 true/false
- exec(str):回傳第一組匹配結果(含群組),無則 null
範例:
```js
const re = /cat/g;
console.log(re.test("a cat")); // true
console.log(re.exec("a cat")); // ["cat", index:2, …]
```
2. String 物件方法
- match(re):回傳所有匹配(若無 g,則回傳第一組)
- replace(re, repl):替換匹配
- search(re):回傳第一個匹配的索引
- split(re):以正則為分隔符拆分字串
範例:
```js
"a1b2c3".match(/\d/g); // ["1","2","3"]
"foo".replace(/o/g, "0"); // "f00"
"hello".search(/l+/); // 2
"a,b;c".split(/[,;]/); // ["a","b","c"]
```
五、小結
- 宣告:Literal (/…/flags) 或 Constructor
- 標誌:g, i, m, u, s, y
- 元件:字元類別、量詞、錨點、群組、前瞻/後顧
- 常用方法:test, exec, match, replace, search, split
多多練習、並利用線上工具(如 regex101.com)測試,即可快速上手!如果有特定範例需求,歡迎再詢問~
---
---
# 📘 字串處理
```js
var mainString = "Hello, world!";
var subString = "world";
console.log(mainString.length); // 字串長度:13
console.log(subString.length); // 字串長度:5
if (mainString.includes(subString)) {
console.log("字串包含指定的子字串");
} else {
console.log("字串不包含指定的子字串");
}
var sentence = "This is a sample sentence.";
var words = sentence.split(" "); // 將句子按空格切割成單字陣列
console.log(words); // ["This", "is", "a", "sample", "sentence."]
var originalStr = "Hello, world!";
var subStr1 = originalStr.substring(0, 5); // 從索引 0 到索引 4 的子字串
var subStr2 = originalStr.substr(7, 5); // 從索引 7 開始,取 5 個字元的子字串
console.log(subStr1); // "Hello"
console.log(subStr2); // "world"
```
### 模板字串(Template literals):
使用模板字串可以更清晰地格式化字串,通過在字串周圍使用反引號,全在字串中使用${}來插入變數。例如:
```js
var name = "John";
var age = 30;
var formattedString = `My name is ${name} and I am ${age} years old.`;
console.log(formattedString);
```
---
---
# 📘 Selector
## ✅ `document.querySelectorAll(selector)`
**功能**:
從整個網頁(`document`)中,根據 CSS 選擇器選取「所有符合條件的元素」。
**回傳值**:
一個 `NodeList`(類陣列),可使用 `forEach` 遍歷。
**語法**:
```js
document.querySelectorAll('div.my-class')
```
**範例**:
```html
<div class="my-class">A</div>
<div class="my-class">B</div>
```
```js
const nodes = document.querySelectorAll('div.my-class');
nodes.forEach(el => console.log(el.textContent)); // 依序輸出 A, B
```
---
## ✅ `div.querySelector(selector)`
**功能**:
從指定的 DOM 節點(如某個 `div`)中,查詢**第一個**符合 CSS 選擇器的「子元素」。
**回傳值**:
一個 `Element` 或 `null`
**語法**:
```js
const first = div.querySelector('.inner');
```
**範例**:
```html
<div id="container">
<span class="inner">Hello</span>
<span class="inner">World</span>
</div>
```
```js
const container = document.getElementById('container');
const firstInner = container.querySelector('.inner');
console.log(firstInner.textContent); // Hello(只找第一個)
```
---
## 🆚 差異總覽
| 比較項目 | `document.querySelectorAll` | `div.querySelector` |
| ----- | --------------------------- | ------------------- |
| 查詢範圍 | 整個網頁 | 限定某個元素底下 |
| 回傳類型 | `NodeList`(所有符合) | 第一個符合的元素 or `null` |
| 支援選擇器 | ✅ 支援完整 CSS 選擇器語法 | ✅ 相同 |
| 用途 | 全域查詢 | 區域查詢 |
---
## 👀 延伸補充
| 方法 | 說明 |
| -------------------------------------- | ------------ |
| `document.querySelector('selector')` | 全頁中找第一個符合的元素 |
| `element.querySelectorAll('selector')` | 在某元素下找所有符合的 |
---
## ✅ 常見選擇器語法
以下是常見的 CSS 選擇器類型,均可用於 `querySelector` / `querySelectorAll`:
| 語法 | 說明 | 範例 |
| ---------------- | --------- | ------------------------------------ |
| `tag` | 標籤名稱 | `'div'`、`'input'` |
| `.class` | 類別 | `'.my-class'` |
| `#id` | ID | `'#my-id'` |
| `[attr]` | 屬性存在 | `'[disabled]'`、`'[type]'` |
| `[attr=value]` | 屬性等於值 | `'[type="text"]'`、`'[name="email"]'` |
| `parent child` | 子層級 | `'ul li'`、`'#form input'` |
| `parent > child` | 直接子層級 | `'form > input'` |
| `A + B` | 緊鄰的兄弟元素 | `'label + input'` |
| `A ~ B` | 所有後面的兄弟元素 | `'h2 ~ p'` |
| `:first-child` | 第一個子元素 | `'li:first-child'` |
| `:last-child` | 最後一個子元素 | `'tr:last-child'` |
| `:nth-child(n)` | 第 n 個子元素 | `'li:nth-child(2)'` |
| `:not(selector)` | 排除選擇器 | `'input:not([type="submit"])'` |
---
## ✅ 範例說明
```js
// 取得所有 class 為 "box" 的 div
document.querySelectorAll('div.box');
// 取得 id 為 "main" 底下的第一個 input
document.querySelector('#main input');
// 取得所有 type 為 checkbox 的 input
document.querySelectorAll('input[type="checkbox"]');
// 取得 class 為 .btn 且未 disabled 的按鈕
document.querySelectorAll('button.btn:not([disabled])');
```
---
## ⚠️ 注意事項
1. 傳入的字串必須是 **合法的 CSS 選擇器**,否則會拋出錯誤(SyntaxError)。
2. 如果選擇器中有特殊字元(如空白、點號),記得要用引號包起來。
```js
// 1. 建立一個 <textarea> 元素
var ta = document.createElement('textarea');
// 2. 設定屬性
ta.id = 'myTextarea';
ta.rows = 5;
ta.cols = 40;
ta.placeholder = '在此輸入內容…';
// 3. 新增到 body 底部
document.body.appendChild(ta);
```
---
---
# 📘 JSON
---
## 1. `JSON.stringify` — 將 JavaScript 物件轉成 JSON 字串
* **用途**:把 JS 物件、陣列等,轉成符合 JSON 格式的字串(文字)。
* **用途場景**:要把資料存成字串(例如存在 localStorage、送到後端 API)
### 範例
```js
const obj = { name: "Adam", age: 30, hobbies: ["coding", "music"] };
// 轉成 JSON 字串
const jsonStr = JSON.stringify(obj);
console.log(jsonStr);
// 輸出: '{"name":"Adam","age":30,"hobbies":["coding","music"]}'
console.log(typeof jsonStr); // "string"
```
---
## 2. `JSON.parse` — 將 JSON 字串轉回 JavaScript 物件
* **用途**:把 JSON 格式的字串,轉成可用的 JS 物件或陣列。
* **用途場景**:收到 API 回傳 JSON 字串,或從 localStorage 讀取的字串資料。
### 範例
```js
const jsonStr = '{"name":"Adam","age":30,"hobbies":["coding","music"]}';
// 轉回 JS 物件
const obj = JSON.parse(jsonStr);
console.log(obj.name); // Adam
console.log(obj.hobbies[1]); // music
console.log(typeof obj); // "object"
```
---
## 注意事項
* `JSON.parse` 的輸入必須是**合法的 JSON 字串**,否則會拋錯。
* `JSON.stringify` 只能轉換 JS 可序列化的資料(函式、`undefined`、Symbol 無法轉換)。
---
## 綜合範例
```js
const user = {
id: 1,
name: "Adam",
active: true,
};
// 物件 → JSON 字串
const json = JSON.stringify(user);
// 將 JSON 字串存到 localStorage
localStorage.setItem("user", json);
// 從 localStorage 讀取
const storedJson = localStorage.getItem("user");
// JSON 字串 → 物件
const parsedUser = JSON.parse(storedJson);
console.log(parsedUser.name); // Adam
```
---
---
# 📘 嚴格模式
嚴格模式(Strict Mode)是 JavaScript 在 ES5 以後新增的一種「加強版」執行環境,目的是讓語言更安全、錯誤更早被抓到,也避免一些容易引起混亂的行為。
---
## 嚴格模式簡介
### 1. **開啟方式**
在 JS 檔案或函式最頂端加一行:
```js
"use strict";
```
---
### 2. **主要改變**
* 禁止使用未宣告的變數(避免意外創造全域變數)
* 函式內的 `this` 若沒指定呼叫對象,會是 `undefined`,而不是全域物件 `window`
* 禁止刪除不能刪除的屬性
* 禁止重複參數名稱
* 禁止用 `with` 語句
* 其他讓錯誤更早暴露的限制
---
### 3. **對 Java 使用者的幫助**
* Java 是靜態型別且嚴格的語言,JavaScript 本質比較寬鬆,很容易不小心寫錯不被發現。
* **嚴格模式讓 JS 更嚴謹、更接近 Java 的「錯誤早報」特性**,讓你寫程式時更安心。
* `this` 行為更合理:普通函式沒呼叫對象時 `this` 是 `undefined`,避免你誤用全域物件導致難查錯的 bug。
---
### 4. **簡單範例**
```js
"use strict";
function foo() {
console.log(this);
}
foo(); // undefined(非嚴格模式下是 window)
```
---
---
# 📘 Web Worker 筆記
---
## ✅ 什麼是 Web Worker?
**Web Worker 是一種瀏覽器 API**,可以讓 JavaScript 在主執行緒以外的背景執行緒中執行程式碼,解決 UI 被卡住的問題。
---
### 🧠 背景:JS 是單執行緒的
* 所有 JS 執行都在「主執行緒」(UI Thread)
* 若做大量計算(例如 for-loop、圖片處理、大資料分析),UI 會「卡住」
* Web Worker 讓你把這類運算搬到背景執行,不影響主執行緒
---
## 🧪 範例 1:用外部 `.js` 檔建立 Worker
### 📄 `index.html`
```html
<!DOCTYPE html>
<html>
<body>
<button id="btn">開始運算</button>
<p id="result">尚未執行</p>
<script>
const worker = new Worker("worker.js");
const btn = document.getElementById("btn");
const result = document.getElementById("result");
btn.addEventListener("click", () => {
result.textContent = "背景運算中...";
worker.postMessage("start");
});
worker.onmessage = (e) => {
result.textContent = "結果:" + e.data;
};
</script>
</body>
</html>
```
---
### 📄 `worker.js`
```js
onmessage = function (e) {
if (e.data === "start") {
let sum = 0;
for (let i = 0; i < 1e9; i++) {
sum += i;
}
postMessage(sum);
}
};
```
---
## 🧪 範例 2:用 `Blob` 建立 Inline Worker(無需額外 `.js` 檔)
```html
<script>
const workerCode = `
self.onmessage = function (e) {
if (e.data === "start") {
let sum = 0;
for (let i = 0; i < 1e9; i++) {
sum += i;
}
self.postMessage(sum);
}
};
`;
const blob = new Blob([workerCode], { type: "application/javascript" });
const worker = new Worker(URL.createObjectURL(blob));
worker.postMessage("start");
worker.onmessage = (e) => console.log("結果:", e.data);
</script>
```
---
## 🔁 主執行緒 ↔ Worker 的溝通方式
| 動作 | API 說明 |
| ------------ | ---------------------------- |
| 發送訊息給 worker | `worker.postMessage(data)` |
| 接收 worker 回覆 | `worker.onmessage = ...` |
| Worker 端接收訊息 | `onmessage = function(e) {}` |
| Worker 回傳主線程 | `postMessage(data)` |
---
## 📌 限制與注意事項
* Worker **無法操作 DOM**
* Worker **不能存取 `window`、`document`、`alert`**
* 可以使用 `fetch`、`setTimeout`、自己定義的函式等
* 與主執行緒間的資料傳遞會經過序列化(建議傳簡單資料或使用 Transferable Object)
---
## ✅ 適用情境
| 任務類型 | 適合用 Worker? | 備註 |
| ------------ | ----------- | ---------------- |
| 長時間 for-loop | ✅ | 可避免 UI 卡頓 |
| 檔案壓縮 / 解壓縮 | ✅ | 類似 zip、json 格式處理 |
| 圖片處理、濾鏡 | ✅ | 不可在主執行緒做太久 |
| 畫面控制、DOM 更新 | ❌ | 不可在 Worker 執行 |
---
## 🧠 與其他技術比較
| 技術 | 執行緒 | 是否能避免 UI 卡住 | 適用於重運算? | 是否能操作 DOM |
| ------------ | -------- | ---------------- | ------- | --------- |
| `setTimeout` | 主執行緒 | ✅ 可稍微緩解 | ❌ 仍占用主緒 | ✅ |
| `await` | 主執行緒(暫停) | ❌ 若是同步 heavy 還是卡 | ❌ | ✅ |
| Web Worker | 背景執行緒 | ✅✅ | ✅✅ | ❌ |
---
## 🧩 Bonus:模組化 Worker(ES Modules 支援)
```js
const worker = new Worker("worker.mjs", { type: "module" });
```
* 支援 `import/export` 語法
* 較新瀏覽器才支援
---
## ✅ 小結筆記
* Web Worker 是瀏覽器提供的真正背景執行環境
* 適用於**長時間、重運算邏輯**
* 無法操作 DOM,僅能與主執行緒訊息傳遞
* 可以透過 `Blob` 內建 Worker,不需額外檔案
---
## ✅ `runWorkerTask` — 通用封裝
### ✅ 功能特性:
* 可 `await`
* 支援 `timeout`(防止 worker 沉默)
* 支援 `error` 捕捉
* 支援一次性通信(worker 結果回來就 resolve)
---
## 📄 用法示範:
```js
const worker = new Worker("worker.js");
try {
const result = await runWorkerTask(worker, { action: "start" }, { timeout: 5000 });
console.log("結果:", result);
} catch (err) {
console.error("Worker 錯誤:", err.message);
}
```
---
## 🧠 封裝函式內容:
```js
function runWorkerTask(worker, message, options = {}) {
const { timeout = 10000 } = options;
return new Promise((resolve, reject) => {
let timeoutId;
// 成功事件
const handleMessage = (e) => {
clearTimeout(timeoutId);
cleanup();
resolve(e.data);
};
// 錯誤事件
const handleError = (e) => {
clearTimeout(timeoutId);
cleanup();
reject(new Error(`Worker error: ${e.message}`));
};
// 清除事件監聽器
const cleanup = () => {
worker.removeEventListener("message", handleMessage);
worker.removeEventListener("error", handleError);
};
// 加入事件監聽器
worker.addEventListener("message", handleMessage);
worker.addEventListener("error", handleError);
// 設定逾時處理
timeoutId = setTimeout(() => {
cleanup();
reject(new Error("Worker timeout"));
}, timeout);
// 發送訊息
worker.postMessage(message);
});
}
```
---
## 🔧 `worker.js`(簡單範例)
```js
self.onmessage = (e) => {
if (e.data.action === "start") {
let sum = 0;
for (let i = 0; i < 1e8; i++) sum += i;
self.postMessage({ result: sum });
}
};
```
---
## 🧠 額外細節說明
| 功能 | 說明 |
| --------------------- | ---------------------------------------------- |
| `removeEventListener` | 避免 memory leak,保證只對一次通信負責 |
| `timeout` | 避免 worker 無限沒回應卡住 Promise |
| `onerror` | 捕捉 syntax error 或 runtime error |
| 傳入 `message` 格式 | 自定義,可用 `{ action: "...", payload: ... }` 模式更清晰 |
---
## 🧠 進階建議(可選)
* 若要支援多次請求同一個 worker,可加 `requestId` 區分(模擬 RPC)
* 若要支援「工作取消」,可擴充 abort 機制(搭配 `AbortController`)
---
## ✅ 小結:你現在擁有的封裝
* 支援 `await`
* 支援逾時
* 安全清除事件監聽
* 可傳任意訊息
* 可應用於所有單次 worker request/response 場景
---
---
---
---
---
---
---
---
---
---
---
---
---
---
### [談談 JavaScript 的 setTimeout 與 setInterval](https://kuro.tw/posts/2019/02/23/%E8%AB%87%E8%AB%87-JavaScript-%E7%9A%84-setTimeout-%E8%88%87-setInterval/)
```js
$('.result-html').html(md.render($('#markdowncontent').text()));
function refreshResult() {
if ("Changed" === $("#response").text()) {
$('.result-html').html(md.render($('#markdowncontent').val()));
}
window.setTimeout(refreshResult, 10000);
}
window.setTimeout(refreshResult, 10000);
```
### JSDoc
```js
/**
* 加法函式
* @param {number} a - 第一個加數
* @param {number} b - 第二個加數
* @returns {number} 兩個數字的和
* @example
* // 使用方式
* var result = add(5, 3);
* console.log(result); // 輸出 8
*/
function add(a, b) {
return a + b;
}
/**
* 計算數字的平方
* @param {number} num - 要計算平方的數字
* @returns {number} 平方值
* @description 這個函式接受一個數字作為參數,並返回該數字的平方值。
*/
function square(num) {
return num * num;
}
```
### setTimeout
該函式用於在指定的時間延遲後執行一次程式碼。
```js
setTimeout(function() {
console.log("這段程式碼將在 2 秒後執行");
}, 2000);
```
### setInterval
該函式用於以指定的間隔重複執行程式碼。
```js
// 使用 setInterval() 每隔 1 秒重複執行程式碼
let counter = 0;
const intervalId = setInterval(function() {
console.log("每秒執行一次,目前計數:" + counter);
counter++;
// 設定停止條件
if (counter === 5) {
clearInterval(intervalId); // 停止執行
}
}, 1000);
```
### Base64編碼和解碼
```js
// 编碼
var originalString = "Hello, World!";
var encodedString = btoa(originalString);
console.log("Encoded String: " + encodedString);
// 解碼
var decodedString = atob(encodedString);
console.log("Decoded String: " + decodedString);
```
### 將 Array 中第一個項目移至另一個 Array
```js
const array1 = [1, 2, 3, 4];
const array2 = [];
const firstItem = array1.shift(); // 移除 array1 的第一個項目並返回該項目
array2.push(firstItem); // 將該項目添加到 array2
console.log(array1); // 輸出:[2, 3, 4]
console.log(array2); // 輸出:[1]
```
### List
```js
var fruits = ["apple", "banana", "orange"];
var joinedFruits = fruits.join(", "); // 將陣列元素以逗號和空格分隔合併為一個字串
console.log(joinedFruits); // "apple, banana, orange"
var numbers = [1, 2, 3, 4, 5];
var joinedNumbers = numbers.join("-"); // 將陣列元素以破折號分隔合併為一個字串
console.log(joinedNumbers); // "1-2-3-4-5"
var text = "Hello";
var joinedText = Array.from(text).join(" "); // 將字串分隔合併為一個字串,以空格分隔字母
console.log(joinedText); // "H e l l o"
```
### Map
```js
// 定義一個文字對應函式的映射物件
const functionMap = {
'greet': function() {
console.log('Hello!');
},
'add': function(a, b) {
return a + b;
},
'multiply': function(a, b) {
return a * b;
}
};
// 使用映射物件執行相應的函式
functionMap['greet'](); // 印出 "Hello!"
const result1 = functionMap['add'](3, 5); // result1 = 8
const result2 = functionMap['multiply'](2, 4); // result2 = 8
```
### Class
```js
// 定義一個名為 "Person" 的類別
function Person(name, age) {
// 類別的建構子,用來初始化物件的屬性
this.name = name;
this.age = age;
}
// 在類別的原型上定義方法
Person.prototype.sayHello = function() {
console.log(`Hello, my name is ${this.name} and I am ${this.age} years old.`);
};
// 在類別的原型上定義共用的屬性(可選)
Person.prototype.nationality = 'Unknown';
// 創建一個 Person 物件
const person1 = new Person('Alice', 25);
const person2 = new Person('Bob', 30);
// 呼叫物件的方法
person1.sayHello(); // 輸出:Hello, my name is Alice and I am 25 years old.
person2.sayHello(); // 輸出:Hello, my name is Bob and I am 30 years old.
// 存取共用的屬性
console.log(person1.nationality); // 輸出:Unknown
console.log(person2.nationality); // 輸出:Unknown
```
```js
class Person {
constructor(name, age) {
this.name = name;
this.age = age;
}
sayHello() {
console.log(`Hello, my name is ${this.name} and I am ${this.age} years old.`);
}
static staticMethod() {
console.log('This is a static method.');
}
}
const person1 = new Person('Alice', 25);
const person2 = new Person('Bob', 30);
person1.sayHello(); // 輸出:Hello, my name is Alice and I am 25 years old.
person2.sayHello(); // 輸出:Hello, my name is Bob and I am 30 years old.
Person.staticMethod(); // 輸出:This is a static method.
```
### MD5
```html
<script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.1.1/crypto-js.min.js"></script>
```
```js
// 要計算 MD5 的字串
const inputString = 'Hello, World!';
// 計算 MD5 雜湊
const md5Hash = CryptoJS.MD5(inputString);
// 將 MD5 雜湊轉換為字串
const md5String = md5Hash.toString();
// 輸出 MD5 雜湊
console.log(md5String);
```
### ISO 8601 Duration 時間操作
```html
<!DOCTYPE html>
<html lang="zh-Hant">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>日期操作範例</title>
<!-- 引入 luxon 库 -->
<script src="https://moment.github.io/luxon/global/luxon.js"></script>
</head>
<body>
<script>
function manipulateDate(inputDate, duration) {
// 將輸入的日期字串轉換為 DateTime 物件
const currentDate = luxon.DateTime.fromISO(inputDate);
// 解析 ISO 8601 持續時間
const durationObject = luxon.Duration.fromISO(duration);
// 根據持續時間調整日期
const manipulatedDate = currentDate.plus(durationObject);
// 格式化結果日期物件為 "YYYY-MM-DD" 格式的字串
const resultDateStr = manipulatedDate.toISODate();
return resultDateStr;
}
// 示例用法
const inputDate = "2023-11-16";
const duration1 = "P2D";
const duration2 = "-PT1H"; // 循環時間表示法,表示減少一小時
const resultDate1 = manipulateDate(inputDate, duration1);
const resultDate2 = manipulateDate(inputDate, duration2);
console.log(resultDate1); // 輸出: 2023-11-18
console.log(resultDate2); // 輸出: 2023-11-16
</script>
</body>
</html>
```
### == VS ===
在 JavaScript 中,`==` 和 `===` 是用來比較兩個值是否相等的運算符,但它們之間有一些重要的差異:
1. `==` (Equality Operator):
- 使用`==`進行比較時,JavaScript 會在比較之前進行類型轉換。
- 如果比較的兩個值的類型不同,JavaScript 會嘗試將它們轉換為相同的類型,然後再進行比較。
- 例如,`'5' == 5` 會返回 `true`,因為 JavaScript 會將字符串 `'5'` 轉換為數字 `5`,然後比較它們的值。
2. `===` (Strict Equality Operator):
- 使用`===`進行比較時,不會進行類型轉換。
- 如果比較的兩個值的類型不同,`===` 將直接返回 `false`,即使它們的值相等。
- 例如,`'5' === 5` 會返回 `false`,因為類型不同。
簡而言之,`==` 允許類型轉換,而 `===` 不允許類型轉換,並要求值和類型都相等。
建議使用 `===` 進行比較,因為它更嚴格,不會引起類型不明確的問題,有助於減少錯誤。
### forEach
```javascript
const numbers = [1, 2, 3, 4, 5];
numbers.forEach(function (number) {
console.log(number);
});
numbers.forEach(number => console.log(number));
```
### map
```javascript
const numbers = [1, 2, 3, 4, 5];
const squaredNumbers = numbers.map(function (number) {
return number * number;
});
// same with
squaredNumbers = numbers.map(number => number * number);
console.log(squaredNumbers);
```
### onclick 帶參數
```html
<!DOCTYPE html>
<html>
<head>
<title>Button Onclick Function with Parameter Example</title>
<script>
function handleButtonOnClick(param) {
alert("Button clicked with parameter: " + param);
}
</script>
</head>
<body>
<button onclick="handleButtonOnClick('example')">Click Me</button>
</body>
</html>
```
在這個例子中,當按下按鈕時會觸發 `handleButtonOnClick` 函式,並且將字串 `example` 傳遞作為參數。當按下按鈕時,會彈出一個警告對話框,顯示出按鈕被點擊的訊息。
### async function
在 JavaScript 中,async 函數是一種用來處理異步操作的函數。當一個函數被聲明為 async 時,該函數內部的代碼會被當做 Promise 對象執行,並且可以使用 await 關鍵字來等待異步操作的完成。
簡單來說,async 函數允許你以同步的方式編寫異步操作的程式碼,使得程式碼更易讀且更易維護。當調用 async 函數時,該函數將返回一個 Promise 對象,可以使用 then 方法來處理成功的結果,也可以使用 catch 方法來處理錯誤的情況。
以下是一個示例,展示了如何定義一個 async 函數並使用 await 關鍵字來等待異步操作的完成:
```javascript
async function fetchData(url) {
const response = await fetch(url);
const data = await response.json();
return data;
}
fetchData('https://api.example.com/data')
.then(data => console.log(data))
.catch(error => console.error(error));
```
### await
在 JavaScript 中,await 關鍵字用於等待一個 promise 物件變為 resolved 狀態(成功)或 rejected 狀態(失敗)後再繼續執行程式碼。在使用 await 時,必須在 async 函數內部使用。例如:
```javascript
async function fetchData() {
try {
const response = await fetch('https://api.example.com/data');
const data = await response.json();
console.log(data);
} catch (error) {
console.error(error);
}
}
fetchData();
```
在上面的例子中,fetchData 函數是一個 async 函數,其中使用了 await 來等待 fetch 和 response.json() 這兩個 promise 物件的解析結果。在最後,我們可以使用 try/catch 塊來處理可能的錯誤。
# map
在 JavaScript 中,要把一個陣列(串列)裡每個物件的兩個欄位,轉成另一種物件的兩個欄位,並集成回一個新陣列,最簡單的方法就是用 Array.prototype.map()。下面用一個完整範例來說明。
---
範例情境
假設你有一個使用者清單,每個物件長這樣:
```js
const users = [
{ id: 1, name: '小明', age: 20, city: '台北' },
{ id: 2, name: '小華', age: 25, city: '新北' },
{ id: 3, name: '小美', age: 22, city: '台中' }
];
```
現在你只想要每個人 `id` 跟 `city` 這兩個欄位,並且想把它們對應到新物件裡的 `userId` 和 `location`,最後把所有新物件組成一個新陣列。
---
作法一:用 map + 解構賦值
```js
const transformed = users.map(({ id, city }) => {
return {
userId: id,
location: city
};
});
console.log(transformed);
/*
[
{ userId: 1, location: '台北' },
{ userId: 2, location: '新北' },
{ userId: 3, location: '台中' }
]
*/
```
重點說明
1. `.map()` 會對原陣列的每個元素呼叫一次傳入的函式,並把函式回傳的值收集成一個新陣列。
2. `({ id, city })` 是解構賦值,直接從 `users` 裡的物件取出 `id`、`city` 兩個欄位。
3. 回傳的新物件 `{ userId: id, location: city }` 便是我們要的格式。