作為 PHP 後端開發者,掌握 JavaScript 核心機制不僅能寫出更好的前端交互,更能在 SSR、BFF、Node.js 微服務場景中游刃有餘。本文系統梳理字符串轉義規則、Date 時間處理、DOM 操作模式、事件流與 Event 對象跨瀏覽器差異。
// 雙引號字符串內嵌雙引號、單引號字符串內嵌單引號必須轉義
const str1 = "my mother say:\"don't speak with stranger\".";
const str2 = 'my mother say:"don\'t speak with stranger".';
// 常用轉義序列
// \" 雙引號 \' 單引號 \\ 反斜杠
// \n 換行(LF) \r 回車(CR) \t 制表符
// \uXXXX Unicode 碼點 (如 \u4e2d = '中')
// \xXX Latin-1 字節 (較少用)
// 關鍵認知:\n \r \t 等與普通字符 'a' 'b' 同層級,都是字符串中的一個代碼點
// 字符串長度計算包含轉義後的單字符:'a\nb'.length === 3
// 構造方式
const d1 = new Date(); // 當前時間
const d2 = new Date("2023/09/25 11:18:19"); // 字符串解析 (建議 ISO 8601: "2023-09-25T11:18:19")
const d3 = new Date(2023, 8, 25, 11, 18, 19); // 年、月(0-11)、日、時、分、秒
const d4 = new Date(1695611899000); // 毫秒時間戳 (自 1970-01-01 UTC)
// 核心本質:Date 內部只存一個 Number (毫秒數),負值表示 1970 年前
// 所有 get/set 方法只是對這個毫秒數按時區/日曆規則的投影
// 獲取組件 (本地時間)
d.getFullYear(); // 年 (四位)
d.getMonth(); // 月 0-11 ⚠️ 易錯點
d.getDate(); // 日 1-31
d.getDay(); // 星期 0(日)-6(六)
d.getHours(); // 時 0-23
d.getMinutes(); // 分
d.getSeconds(); // 秒
d.getMilliseconds(); // 毫秒
d.getTime(); // 毫秒時間戳 (同 valueOf())
d.toLocaleString(); // 本地化字符串 (格式依運行環境)
// 設置組件 (本地時間)
d.setFullYear(2024);
d.setMonth(11); // 12月
// ... 同理
// 靜態方法
Date.now(); // 當前毫秒戳 (性能優於 new Date().getTime())
Date.parse(str); // 字符串解析為毫秒戳
Date.UTC(y,m,d,...); // 組件構造 UTC 毫秒戳 (月 0-11)
// 核心觀念:HTML 標簽即對象,屬性即錮性,樣式即 style 對象屬性
// 1. 獲取元素
const el = document.getElementById('my-id'); // 單元素
const list = document.querySelectorAll('.cls'); // NodeList (靜態)
const live = document.getElementsByClassName('cls'); // HTMLCollection (動態)
// 2. 屬性操作 (Attribute vs Property)
// Attribute: HTML 寫死的初始值 -> el.getAttribute('id') / el.setAttribute('id', 'new')
// Property: JS 對象實時狀態 -> el.id = 'new' / el.checked / el.value
// 表單元素值、勾選狀態、disabled **必須用 Property**
// 3. 樣式操作
el.style.color = 'red'; // 行內樣式 (高優先級)
// 讀取計算後樣式需用:
getComputedStyle(el).color; // 返回 'rgb(255, 0, 0)'
// 4. 類名操作 (推薦)
el.classList.add('active');
el.classList.remove('hidden');
el.classList.toggle('loading');
el.classList.contains('active'); // boolean
| 類別 | 事件名 | 觸發時機 |
|---|---|---|
| 鼠標 | click | 點擊完成 (mousedown + mouseup 同元素) |
| dblclick | 雙擊 | |
| mousedown | 按下 (未釋放) | |
| mouseup | 釋放 | |
| mouseover | 進入元素 (冒泡) | |
| mouseout | 離開元素 (冒泡) | |
| mousemove | 移動 (高頻,需節流) | |
| 鍵盤 | keydown | 按下 (持續觸發) |
| keyup | 釋放 | |
| keypress | 字符輸入 (已棄用,用 keydown + event.key) | |
| 表單 | submit | 表單提交前 (可 preventDefault 阻止) |
| focus | 獲得焦點 | |
| blur | 失去焦點 | |
| change | 值改變並失焦 (select/checkbox/radio 即時) | |
| 窗口 | load | 頁面所有資源加載完成 (僅一次) |
| 文檔 | DOMContentLoaded | HTML 解析完成 (不等待圖片/CSS) |
// 現代標準:addEventListener (支援捕獲/冒泡、多監聽器、this 綁定)
element.addEventListener('click', handler, { passive: true, once: false, capture: false });
// 事件對象 event (傳入處理函數第一個參數)
function handler(event) {
// 坐標
event.clientX / event.clientY; // 視口座標
event.pageX / event.pageY; // 文檔座標 (含滾動)
event.offsetX / event.offsetY; // 相對目標元素 padding 邊緣
// 目標元素
event.target; // 實際觸發元素 (冒泡階段可能非綁定元素)
event.currentTarget; // 綁定監聽器的元素 (=== this)
// 鍵盤
event.key; // 字符值 ("Enter", "a", "ArrowLeft")
event.code; // 物理鍵碼 ("KeyA", "Enter")
event.ctrlKey/shiftKey/altKey/metaKey; // 修飾鍵狀態
// 阻止默認/冒泡
event.preventDefault(); // 阻止默認行為 (如表單提交、鏈接跳轉)
event.stopPropagation(); // 阻止冒泡
event.stopImmediatePropagation(); // 阻止同元素其他監聽器
}
<button id="btn" onclick="handler1(this)">Btn</button>
<button id="btn2" onclick="handler2(event)">Btn2</button>
function handler1(el) {
// el === document.getElementById('btn') (綁定元素)
el.style.background = 'red';
}
function handler2(evt) {
// evt.target === 實際點擊元素 (可能是按鈕內部的 span)
// evt.currentTarget === 綁定元素 (btn2)
console.log(evt.clientX, evt.target.tagName);
}
new Date(2023, 8, 1) 是 9 月 1 日,PHP date('m') 是 1-12。*1000 / /1000。if (e.target.matches('.item'))。將 JavaScript 視為「運行在瀏覽器/Node.js 中的獨立語言」而非「頁面裝飾腳本」,用工程化思維掌握其核心模型,全棧開發才能真正融會貫通。