JavaScript笔记
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>📘 JavaScript 核心笔记 · 中等难度</title>
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link href="https://fonts.googleapis.com/css2?family=Inter:opsz@14..32&family=JetBrains+Mono:wght@400;600&display=swap" rel="stylesheet" />
<style>
/* ===== 基础重置 & 全局 ===== */
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Inter', system-ui, -apple-system, sans-serif;
background: #f1f5f9;
color: #0b1120;
line-height: 1.6;
padding: 2rem 1rem;
}
.container {
max-width: 1100px;
margin: 0 auto;
background: #ffffff;
padding: 2.5rem 2.8rem;
border-radius: 28px;
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.06);
}
/* ===== 头部 ===== */
.header {
margin-bottom: 2.5rem;
border-bottom: 2px solid #eef2f6;
padding-bottom: 1.8rem;
}
.header h1 {
font-size: 2.6rem;
font-weight: 700;
letter-spacing: -0.02em;
background: linear-gradient(135deg, #d97706, #dc2626);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
display: inline-block;
}
.header .sub {
display: block;
font-size: 1rem;
color: #475569;
margin-top: 0.4rem;
font-weight: 400;
-webkit-text-fill-color: #475569;
}
/* ===== 通用组件 ===== */
section {
margin-bottom: 3rem;
}
h2 {
font-size: 1.6rem;
font-weight: 600;
letter-spacing: -0.01em;
color: #0b1120;
display: flex;
align-items: center;
gap: 0.6rem;
margin-bottom: 1.2rem;
}
h2 .badge {
font-size: 0.7rem;
font-weight: 500;
background: #fef3c7;
color: #b45309;
padding: 0.15rem 0.8rem;
border-radius: 40px;
letter-spacing: 0.01em;
}
h3 {
font-size: 1.1rem;
font-weight: 600;
margin: 1.6rem 0 0.6rem 0;
color: #1e293b;
}
.grid-2col {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 1.8rem;
margin: 1rem 0;
}
.card {
background: #f9fbfd;
border-radius: 18px;
padding: 1.4rem 1.6rem;
border: 1px solid #edf2f7;
transition: background 0.15s;
}
.card:hover {
background: #f1f5f9;
}
.card h4 {
font-weight: 600;
font-size: 1rem;
margin-bottom: 0.5rem;
color: #0b1120;
}
.card p,
.card li {
color: #334155;
font-size: 0.95rem;
}
.card ul {
list-style: none;
padding: 0;
margin-top: 0.4rem;
}
.card ul li {
padding: 0.2rem 0 0.2rem 1.4rem;
position: relative;
}
.card ul li::before {
content: "▹";
position: absolute;
left: 0;
color: #d97706;
font-weight: 600;
}
/* ===== 代码块 (JS 高亮风格) ===== */
.code-block {
background: #0b1120;
color: #e2e8f0;
padding: 1.2rem 1.6rem;
border-radius: 16px;
font-family: 'JetBrains Mono', 'Fira Code', monospace;
font-size: 0.85rem;
overflow-x: auto;
margin: 0.8rem 0 1.2rem 0;
line-height: 1.8;
white-space: pre-wrap;
word-break: break-word;
border: 1px solid #1e293b;
}
.code-block .comment { color: #94a3b8; font-style: italic; }
.code-block .keyword { color: #c084fc; } // const, let, function, etc.
.code-block .string { color: #34d399; } // "hello"
.code-block .number { color: #fbbf24; } // 42
.code-block .func { color: #60a5fa; } // console.log
.code-block .variable { color: #f472b6; } // 变量名
.code-block .operator { color: #f472b6; } // =, +, =>
.code-block .bracket { color: #e2e8f0; }
.inline-code {
background: #eef2f6;
color: #1e293b;
padding: 0.15rem 0.5rem;
border-radius: 6px;
font-family: 'JetBrains Mono', monospace;
font-size: 0.85rem;
font-weight: 500;
}
/* ===== 提示框 ===== */
.tip {
background: #ecfdf5;
border-left: 4px solid #10b981;
padding: 0.8rem 1.2rem;
border-radius: 12px;
margin: 1.2rem 0;
color: #065f46;
}
.tip strong { color: #047857; }
.warning {
background: #fffbeb;
border-left: 4px solid #f59e0b;
padding: 0.8rem 1.2rem;
border-radius: 12px;
margin: 1.2rem 0;
color: #92400e;
}
.warning strong { color: #b45309; }
.demo-box {
display: flex;
gap: 0.6rem;
flex-wrap: wrap;
margin: 0.6rem 0;
}
.demo-tag {
background: #dbeafe;
color: #1e3a8a;
padding: 0.2rem 0.9rem;
border-radius: 40px;
font-size: 0.8rem;
font-weight: 500;
}
/* ===== 响应式 ===== */
@media (max-width: 700px) {
.container { padding: 1.5rem 1.2rem; }
.header h1 { font-size: 2rem; }
.grid-2col { grid-template-columns: 1fr; gap: 1rem; }
.code-block { font-size: 0.75rem; padding: 1rem; }
}
.footer {
margin-top: 3rem;
border-top: 1px solid #e2e8f0;
padding-top: 1.5rem;
text-align: center;
color: #64748b;
font-size: 0.9rem;
}
</style>
</head>
<body>
<div class="container">
<!-- ===== 头部 ===== -->
<header class="header">
<h1>🧬 JavaScript 核心笔记</h1>
<span class="sub">中等难度 · 聚焦 ES6+ 实用特性 · 告别基础「小白」阶段</span>
</header>
<!-- ========================================================== -->
<!-- 第一部分:变量与声明 -->
<!-- ========================================================== -->
<section>
<h2>📦 变量声明 <span class="badge">let · const · var</span></h2>
<div class="grid-2col">
<div class="card">
<h4>🔹 let & const (ES6)</h4>
<ul>
<li><span class="inline-code">let</span>:可变变量,块级作用域 <span class="inline-code">{ }</span>。</li>
<li><span class="inline-code">const</span>:常量(不可重新赋值),块级作用域。</li>
<li><span class="inline-code">const</span> 对象/数组内容可变,但引用不可变。</li>
<li><strong>优先使用</strong> <span class="inline-code">const</span>,确实需要修改时用 <span class="inline-code">let</span>。</li>
</ul>
<div class="code-block">
<span class="keyword">let</span> <span class="variable">age</span> <span class="operator">=</span> <span class="number">25</span>;
<span class="variable">age</span> <span class="operator">=</span> <span class="number">26</span>; <span class="comment">// ✅ 可以修改</span>
<span class="keyword">const</span> <span class="variable">birthYear</span> <span class="operator">=</span> <span class="number">1995</span>;
<span class="comment">// birthYear = 1996; ❌ 报错</span>
<span class="keyword">const</span> <span class="variable">user</span> <span class="operator">=</span> <span class="bracket">{</span> <span class="variable">name</span>: <span class="string">'Alice'</span> <span class="bracket">}</span>;
<span class="variable">user</span>.<span class="variable">name</span> <span class="operator">=</span> <span class="string">'Bob'</span>; <span class="comment">// ✅ 内容可变</span>
</div>
<div class="tip">💡 <strong>块级作用域</strong>:<span class="inline-code">if</span>、<span class="inline-code">for</span>、<span class="inline-code">{ }</span> 都会产生块级作用域,<span class="inline-code">var</span> 无视块级(函数级),容易产生 bug,<strong>尽量不用 var</strong>。</div>
</div>
<div class="card">
<h4>🔸 变量提升 (Hoisting)</h4>
<ul>
<li><span class="inline-code">var</span> 会提升到作用域顶部,初始为 <span class="inline-code">undefined</span>。</li>
<li><span class="inline-code">let</span> / <span class="inline-code">const</span> 也会提升,但存在「暂时性死区 (TDZ)」,在声明前访问会报错。</li>
</ul>
<div class="code-block">
<span class="comment">// var 的例子 (不推荐)</span>
<span class="keyword">console</span>.<span class="func">log</span>(<span class="variable">x</span>); <span class="comment">// undefined</span>
<span class="keyword">var</span> <span class="variable">x</span> <span class="operator">=</span> <span class="number">5</span>;
<span class="comment">// let/const TDZ 示例</span>
<span class="comment">// console.log(y); // ❌ ReferenceError</span>
<span class="keyword">let</span> <span class="variable">y</span> <span class="operator">=</span> <span class="number">10</span>;
</div>
</div>
</div>
</section>
<!-- ========================================================== -->
<!-- 第二部分:函数 (箭头函数 & 默认参数) -->
<!-- ========================================================== -->
<section>
<h2>⚡ 函数进阶 <span class="badge">箭头 · 默认值 · 回调</span></h2>
<div class="grid-2col">
<div class="card">
<h4>🏹 箭头函数 (Arrow Function)</h4>
<ul>
<li>更简洁的语法,<strong>没有自己的 <span class="inline-code">this</span></strong>(继承外层作用域)。</li>
<li>如果函数体只有一行 <span class="inline-code">return</span>,可以省略 <span class="inline-code">{ }</span> 和 <span class="inline-code">return</span>(隐式返回)。</li>
</ul>
<div class="code-block">
<span class="comment">// 传统函数</span>
<span class="keyword">function</span> <span class="func">add</span>(<span class="variable">a</span>, <span class="variable">b</span>) <span class="bracket">{</span>
<span class="keyword">return</span> <span class="variable">a</span> <span class="operator">+</span> <span class="variable">b</span>;
<span class="bracket">}</span>
<span class="comment">// 箭头函数</span>
<span class="keyword">const</span> <span class="variable">addArrow</span> <span class="operator">=</span> (<span class="variable">a</span>, <span class="variable">b</span>) <span class="operator">=></span> <span class="variable">a</span> <span class="operator">+</span> <span class="variable">b</span>;
<span class="keyword">const</span> <span class="variable">square</span> <span class="operator">=</span> <span class="variable">x</span> <span class="operator">=></span> <span class="variable">x</span> <span class="operator">*</span> <span class="variable">x</span>; <span class="comment">// 参数仅一个时可省略括号</span>
<span class="comment">// 多行语句需加 {} 和 return</span>
<span class="keyword">const</span> <span class="variable">greet</span> <span class="operator">=</span> (<span class="variable">name</span>) <span class="operator">=></span> <span class="bracket">{</span>
<span class="keyword">const</span> <span class="variable">msg</span> <span class="operator">=</span> <span class="string">`Hello, </span><span class="variable">${name}</span><span class="string">`</span>;
<span class="keyword">return</span> <span class="variable">msg</span>;
<span class="bracket">}</span>;
</div>
</div>
<div class="card">
<h4>📞 默认参数 & 回调</h4>
<ul>
<li><strong>默认参数</strong>:避免 <span class="inline-code">undefined</span> 带来的意外。</li>
<li><strong>回调函数</strong>:作为参数传入其他函数,是异步编程的基础。</li>
</ul>
<div class="code-block">
<span class="comment">// 默认参数</span>
<span class="keyword">function</span> <span class="func">multiply</span>(<span class="variable">a</span>, <span class="variable">b</span> <span class="operator">=</span> <span class="number">1</span>) <span class="bracket">{</span>
<span class="keyword">return</span> <span class="variable">a</span> <span class="operator">*</span> <span class="variable">b</span>;
<span class="bracket">}</span>
<span class="func">multiply</span>(<span class="number">5</span>); <span class="comment">// 5</span>
<span class="comment">// 回调函数 (数组 forEach 示例)</span>
<span class="keyword">const</span> <span class="variable">nums</span> <span class="operator">=</span> <span class="bracket">[</span><span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span><span class="bracket">]</span>;
<span class="variable">nums</span>.<span class="func">forEach</span>(<span class="variable">num</span> <span class="operator">=></span> <span class="bracket">{</span>
<span class="keyword">console</span>.<span class="func">log</span>(<span class="variable">num</span> <span class="operator">*</span> <span class="number">2</span>);
<span class="bracket">}</span>);
</div>
</div>
</div>
</section>
<!-- ========================================================== -->
<!-- 第三部分:数组 & 对象 (解构 + 展开 + 高阶方法) -->
<!-- ========================================================== -->
<section>
<h2>🧩 数组 & 对象操作 <span class="badge">解构 · 展开 · map/filter/reduce</span></h2>
<p style="color:#334155; margin-bottom:0.8rem;">
这部分是 JS 进阶的「分水岭」,熟练使用能让代码更优雅、更函数式。
</p>
<div class="grid-2col">
<div class="card">
<h4>📤 解构赋值 (Destructuring)</h4>
<ul>
<li><strong>数组解构</strong>:按位置提取。</li>
<li><strong>对象解构</strong>:按属性名提取,可重命名。</li>
<li>常用于函数参数、交换变量。</li>
</ul>
<div class="code-block">
<span class="comment">// 数组解构</span>
<span class="keyword">const</span> <span class="variable">colors</span> <span class="operator">=</span> <span class="bracket">[</span><span class="string">'red'</span>, <span class="string">'green'</span>, <span class="string">'blue'</span><span class="bracket">]</span>;
<span class="keyword">const</span> <span class="bracket">[</span><span class="variable">first</span>, <span class="variable">second</span><span class="bracket">]</span> <span class="operator">=</span> <span class="variable">colors</span>;
<span class="keyword">console</span>.<span class="func">log</span>(<span class="variable">first</span>); <span class="comment">// 'red'</span>
<span class="comment">// 对象解构</span>
<span class="keyword">const</span> <span class="variable">user</span> <span class="operator">=</span> <span class="bracket">{</span> <span class="variable">name</span>: <span class="string">'John'</span>, <span class="variable">age</span>: <span class="number">30</span> <span class="bracket">}</span>;
<span class="keyword">const</span> <span class="bracket">{</span> <span class="variable">name</span>, <span class="variable">age</span>: <span class="variable">userAge</span> <span class="bracket">}</span> <span class="operator">=</span> <span class="variable">user</span>;
<span class="keyword">console</span>.<span class="func">log</span>(<span class="variable">name</span>, <span class="variable">userAge</span>); <span class="comment">// 'John' 30</span>
</div>
</div>
<div class="card">
<h4>🔗 展开运算符 (Spread) & 剩余参数 (Rest)</h4>
<ul>
<li><span class="inline-code">...</span> 用于「展开」数组/对象,或「收集」剩余参数。</li>
<li>常用作数组/对象的浅拷贝、合并。</li>
</ul>
<div class="code-block">
<span class="comment">// 数组展开</span>
<span class="keyword">const</span> <span class="variable">arr1</span> <span class="operator">=</span> <span class="bracket">[</span><span class="number">1</span>, <span class="number">2</span><span class="bracket">]</span>;
<span class="keyword">const</span> <span class="variable">arr2</span> <span class="operator">=</span> <span class="bracket">[</span><span class="number">3</span>, <span class="number">4</span><span class="bracket">]</span>;
<span class="keyword">const</span> <span class="variable">merged</span> <span class="operator">=</span> <span class="bracket">[</span>...<span class="variable">arr1</span>, ...<span class="variable">arr2</span><span class="bracket">]</span>; <span class="comment">// [1,2,3,4]</span>
<span class="comment">// 对象展开 (合并)</span>
<span class="keyword">const</span> <span class="variable">obj1</span> <span class="operator">=</span> <span class="bracket">{</span> <span class="variable">a</span>: <span class="number">1</span>, <span class="variable">b</span>: <span class="number">2</span> <span class="bracket">}</span>;
<span class="keyword">const</span> <span class="variable">obj2</span> <span class="operator">=</span> <span class="bracket">{</span> ...<span class="variable">obj1</span>, <span class="variable">c</span>: <span class="number">3</span> <span class="bracket">}</span>; <span class="comment">// {a:1, b:2, c:3}</span>
<span class="comment">// 剩余参数 (函数参数)</span>
<span class="keyword">function</span> <span class="func">sum</span>(...<span class="variable">numbers</span>) <span class="bracket">{</span>
<span class="keyword">return</span> <span class="variable">numbers</span>.<span class="func">reduce</span>((<span class="variable">acc</span>, <span class="variable">n</span>) <span class="operator">=></span> <span class="variable">acc</span> <span class="operator">+</span> <span class="variable">n</span>, <span class="number">0</span>);
<span class="bracket">}</span>
<span class="func">sum</span>(<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>); <span class="comment">// 6</span>
</div>
</div>
</div>
<!-- 数组高阶方法 -->
<h3>🛠️ 必知必会:map / filter / reduce</h3>
<div class="grid-2col">
<div class="card">
<h4>🔁 .map() — 转换</h4>
<p>对每个元素执行操作,<strong>返回新数组</strong>(长度不变)。</p>
<div class="code-block">
<span class="keyword">const</span> <span class="variable">nums</span> <span class="operator">=</span> <span class="bracket">[</span><span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span><span class="bracket">]</span>;
<span class="keyword">const</span> <span class="variable">doubled</span> <span class="operator">=</span> <span class="variable">nums</span>.<span class="func">map</span>(<span class="variable">n</span> <span class="operator">=></span> <span class="variable">n</span> <span class="operator">*</span> <span class="number">2</span>);
<span class="keyword">console</span>.<span class="func">log</span>(<span class="variable">doubled</span>); <span class="comment">// [2, 4, 6]</span>
</div>
</div>
<div class="card">
<h4>🔍 .filter() — 筛选</h4>
<p>返回满足条件的元素组成<strong>新数组</strong>(长度可能变)。</p>
<div class="code-block">
<span class="keyword">const</span> <span class="variable">nums</span> <span class="operator">=</span> <span class="bracket">[</span><span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>, <span class="number">4</span><span class="bracket">]</span>;
<span class="keyword">const</span> <span class="variable">even</span> <span class="operator">=</span> <span class="variable">nums</span>.<span class="func">filter</span>(<span class="variable">n</span> <span class="operator">=></span> <span class="variable">n</span> <span class="operator">%</span> <span class="number">2</span> <span class="operator">===</span> <span class="number">0</span>);
<span class="keyword">console</span>.<span class="func">log</span>(<span class="variable">even</span>); <span class="comment">// [2, 4]</span>
</div>
</div>
<div class="card" style="grid-column: 1 / -1;">
<h4>🧮 .reduce() — 聚合</h4>
<p>将数组归约为单个值(累加、累乘、拼接等)。<strong>面试高频</strong>。</p>
<div class="code-block">
<span class="keyword">const</span> <span class="variable">nums</span> <span class="operator">=</span> <span class="bracket">[</span><span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>, <span class="number">4</span><span class="bracket">]</span>;
<span class="keyword">const</span> <span class="variable">sum</span> <span class="operator">=</span> <span class="variable">nums</span>.<span class="func">reduce</span>((<span class="variable">acc</span>, <span class="variable">cur</span>) <span class="operator">=></span> <span class="variable">acc</span> <span class="operator">+</span> <span class="variable">cur</span>, <span class="number">0</span>);
<span class="keyword">console</span>.<span class="func">log</span>(<span class="variable">sum</span>); <span class="comment">// 10</span>
<span class="comment">// 进阶:统计字符出现次数</span>
<span class="keyword">const</span> <span class="variable">letters</span> <span class="operator">=</span> <span class="bracket">[</span><span class="string">'a'</span>, <span class="string">'b'</span>, <span class="string">'a'</span><span class="bracket">]</span>;
<span class="keyword">const</span> <span class="variable">count</span> <span class="operator">=</span> <span class="variable">letters</span>.<span class="func">reduce</span>((<span class="variable">acc</span>, <span class="variable">char</span>) <span class="operator">=></span> <span class="bracket">{</span>
<span class="variable">acc</span>[<span class="variable">char</span>] <span class="operator">=</span> (<span class="variable">acc</span>[<span class="variable">char</span>] <span class="operator">||</span> <span class="number">0</span>) <span class="operator">+</span> <span class="number">1</span>;
<span class="keyword">return</span> <span class="variable">acc</span>;
<span class="bracket">}</span>, <span class="bracket">{}</span>); <span class="comment">// { a: 2, b: 1 }</span>
</div>
</div>
</div>
</section>
<!-- ========================================================== -->
<!-- 第四部分:DOM 操作 & 事件 -->
<!-- ========================================================== -->
<section>
<h2>🖱️ DOM 交互 <span class="badge">选择 · 事件 · 动态内容</span></h2>
<div class="grid-2col">
<div class="card">
<h4>🎯 选择元素</h4>
<ul>
<li><span class="inline-code">document.querySelector()</span>:返回第一个匹配元素。</li>
<li><span class="inline-code">document.querySelectorAll()</span>:返回所有匹配元素 (NodeList)。</li>
<li>支持 CSS 选择器,非常灵活。</li>
</ul>
<div class="code-block">
<span class="comment">// 通过类选择器</span>
<span class="keyword">const</span> <span class="variable">btn</span> <span class="operator">=</span> <span class="variable">document</span>.<span class="func">querySelector</span>(<span class="string">'.my-button'</span>);
<span class="comment">// 通过 ID</span>
<span class="keyword">const</span> <span class="variable">header</span> <span class="operator">=</span> <span class="variable">document</span>.<span class="func">querySelector</span>(<span class="string">'#main-header'</span>);
<span class="comment">// 所有 li</span>
<span class="keyword">const</span> <span class="variable">items</span> <span class="operator">=</span> <span class="variable">document</span>.<span class="func">querySelectorAll</span>(<span class="string">'ul li'</span>);
</div>
</div>
<div class="card">
<h4>⚡ 事件监听</h4>
<ul>
<li><span class="inline-code">addEventListener</span> 绑定事件,可同时绑定多个。</li>
<li>常用事件:<span class="inline-code">click</span>, <span class="inline-code">input</span>, <span class="inline-code">submit</span>, <span class="inline-code">mouseover</span>。</li>
<li>事件对象 <span class="inline-code">e</span> 包含目标、坐标等信息。</li>
</ul>
<div class="code-block">
<span class="keyword">const</span> <span class="variable">btn</span> <span class="operator">=</span> <span class="variable">document</span>.<span class="func">querySelector</span>(<span class="string">'#myBtn'</span>);
<span class="variable">btn</span>.<span class="func">addEventListener</span>(<span class="string">'click'</span>, (<span class="variable">e</span>) <span class="operator">=></span> <span class="bracket">{</span>
<span class="keyword">console</span>.<span class="func">log</span>(<span class="string">'按钮被点击了!'</span>);
<span class="variable">e</span>.<span class="variable">target</span>.<span class="variable">style</span>.<span class="variable">backgroundColor</span> <span class="operator">=</span> <span class="string">'yellow'</span>;
<span class="bracket">}</span>);
<span class="comment">// 动态创建元素</span>
<span class="keyword">const</span> <span class="variable">newDiv</span> <span class="operator">=</span> <span class="variable">document</span>.<span class="func">createElement</span>(<span class="string">'div'</span>);
<span class="variable">newDiv</span>.<span class="variable">textContent</span> <span class="operator">=</span> <span class="string">'我是动态添加的'</span>;
<span class="variable">document</span>.<span class="variable">body</span>.<span class="func">appendChild</span>(<span class="variable">newDiv</span>);
</div>
</div>
</div>
<div class="tip">💡 <strong>事件委托</strong>:将事件监听挂在父元素上,利用冒泡机制,适用于动态列表,性能更好。</div>
</section>
<!-- ========================================================== -->
<!-- 第五部分:异步编程 (Promise & Async/Await) -->
<!-- ========================================================== -->
<section>
<h2>⏳ 异步编程 <span class="badge">Promise · async/await</span></h2>
<div class="grid-2col">
<div class="card">
<h4>🤝 Promise 基础</h4>
<ul>
<li>表示一个<strong>异步操作的最终结果</strong>(成功或失败)。</li>
<li>状态:<span class="inline-code">pending</span> → <span class="inline-code">fulfilled</span> 或 <span class="inline-code">rejected</span>。</li>
<li>链式调用 <span class="inline-code">.then()</span> 和 <span class="inline-code">.catch()</span>。</li>
</ul>
<div class="code-block">
<span class="keyword">const</span> <span class="variable">fetchData</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="func">Promise</span>((<span class="variable">resolve</span>, <span class="variable">reject</span>) <span class="operator">=></span> <span class="bracket">{</span>
<span class="keyword">setTimeout</span>(() <span class="operator">=></span> <span class="bracket">{</span>
<span class="keyword">const</span> <span class="variable">success</span> <span class="operator">=</span> <span class="keyword">true</span>;
<span class="variable">success</span> <span class="operator">?</span> <span class="func">resolve</span>(<span class="string">'数据加载成功'</span>) <span class="operator">:</span> <span class="func">reject</span>(<span class="string">'出错了'</span>);
<span class="bracket">}</span>, <span class="number">1000</span>);
<span class="bracket">}</span>);
<span class="variable">fetchData</span>
.<span class="func">then</span>(<span class="variable">res</span> <span class="operator">=></span> <span class="keyword">console</span>.<span class="func">log</span>(<span class="variable">res</span>))
.<span class="func">catch</span>(<span class="variable">err</span> <span class="operator">=></span> <span class="keyword">console</span>.<span class="func">log</span>(<span class="variable">err</span>));
</div>
</div>
<div class="card">
<h4>🚀 async / await (语法糖)</h4>
<ul>
<li>让异步代码看起来像同步,<strong>更易读</strong>。</li>
<li><span class="inline-code">async</span> 函数返回 Promise,<span class="inline-code">await</span> 等待结果。</li>
<li>必须用 <span class="inline-code">try...catch</span> 捕获错误。</li>
</ul>
<div class="code-block">
<span class="comment">// 模拟 API 请求</span>
<span class="keyword">async</span> <span class="keyword">function</span> <span class="func">getUser</span>() <span class="bracket">{</span>
<span class="keyword">try</span> <span class="bracket">{</span>
<span class="keyword">const</span> <span class="variable">response</span> <span class="operator">=</span> <span class="keyword">await</span> <span class="func">fetch</span>(<span class="string">'https://api.example.com/user'</span>);
<span class="keyword">const</span> <span class="variable">data</span> <span class="operator">=</span> <span class="keyword">await</span> <span class="variable">response</span>.<span class="func">json</span>();
<span class="keyword">console</span>.<span class="func">log</span>(<span class="variable">data</span>);
<span class="bracket">}</span> <span class="keyword">catch</span> (<span class="variable">error</span>) <span class="bracket">{</span>
<span class="keyword">console</span>.<span class="func">log</span>(<span class="string">'请求失败:'</span>, <span class="variable">error</span>);
<span class="bracket">}</span>
<span class="bracket">}</span>
<span class="func">getUser</span>();
</div>
<div class="warning">⚠️ <strong>注意</strong>:<span class="inline-code">await</span> 只能在 <span class="inline-code">async</span> 函数内部使用。</div>
</div>
</div>
</section>
<!-- ========================================================== -->
<!-- 第六部分:作用域 & 闭包 (简) -->
<!-- ========================================================== -->
<section>
<h2>🔭 作用域 & 闭包 <span class="badge">理解核心</span></h2>
<div class="grid-2col">
<div class="card">
<h4>📦 作用域链</h4>
<ul>
<li><strong>全局作用域</strong>:在任何地方都可以访问。</li>
<li><strong>函数作用域</strong>:<span class="inline-code">var</span> 和传统函数。</li>
<li><strong>块级作用域</strong>:<span class="inline-code">let</span> / <span class="inline-code">const</span>。</li>
<li>内部函数可以访问外部函数的变量(作用域链)。</li>
</ul>
<div class="code-block">
<span class="keyword">let</span> <span class="variable">global</span> <span class="operator">=</span> <span class="string">'全局'</span>;
<span class="keyword">function</span> <span class="func">outer</span>() <span class="bracket">{</span>
<span class="keyword">let</span> <span class="variable">outerVar</span> <span class="operator">=</span> <span class="string">'外部'</span>;
<span class="keyword">function</span> <span class="func">inner</span>() <span class="bracket">{</span>
<span class="keyword">let</span> <span class="variable">innerVar</span> <span class="operator">=</span> <span class="string">'内部'</span>;
<span class="keyword">console</span>.<span class="func">log</span>(<span class="variable">global</span>, <span class="variable">outerVar</span>, <span class="variable">innerVar</span>); <span class="comment">// 都能访问</span>
<span class="bracket">}</span>
<span class="func">inner</span>();
<span class="bracket">}</span>
<span class="func">outer</span>();
</div>
</div>
<div class="card">
<h4>🧊 闭包 (Closure)</h4>
<ul>
<li><strong>定义</strong>:内部函数可以记住并访问其外部函数的变量,即使外部函数已经执行完毕。</li>
<li>常用于封装私有变量、柯里化、防抖/节流。</li>
</ul>
<div class="code-block">
<span class="keyword">function</span> <span class="func">counter</span>() <span class="bracket">{</span>
<span class="keyword">let</span> <span class="variable">count</span> <span class="operator">=</span> <span class="number">0</span>;
<span class="keyword">return</span> <span class="keyword">function</span>() <span class="bracket">{</span>
<span class="variable">count</span><span class="operator">++</span>;
<span class="keyword">return</span> <span class="variable">count</span>;
<span class="bracket">}</span>;
<span class="bracket">}</span>
<span class="keyword">const</span> <span class="variable">increment</span> <span class="operator">=</span> <span class="func">counter</span>();
<span class="func">increment</span>(); <span class="comment">// 1</span>
<span class="func">increment</span>(); <span class="comment">// 2</span>
<span class="comment">// count 变量被「闭包」保护,外部无法直接修改</span>
</div>
</div>
</div>
</section>
<!-- ========================================================== -->
<!-- 第七部分:调试 & 最佳实践 -->
<!-- ========================================================== -->
<section>
<h2>🪲 调试 & 好习惯 <span class="badge">工具 · 规范</span></h2>
<div class="grid-2col">
<div class="card">
<h4>🔧 开发者工具</h4>
<ul>
<li><strong>console.log()</strong>:最常用的调试方法。</li>
<li><strong>console.table()</strong>:以表格形式展示数组/对象。</li>
<li><strong>debugger</strong>:在代码中设置断点。</li>
<li>Chrome DevTools 的 Sources 面板:断点调试、查看调用栈。</li>
</ul>
</div>
<div class="card">
<h4>✅ 编码好习惯</h4>
<ul>
<li>变量/函数命名使用 <span class="inline-code">camelCase</span>(如 <span class="inline-code">getUserData</span>)。</li>
<li>使用 <span class="inline-code">===</span> 代替 <span class="inline-code">==</span>(避免隐式类型转换)。</li>
<li>尽量使用 <span class="inline-code">const</span>,除非需要重新赋值。</li>
<li>使用 <span class="inline-code">try...catch</span> 处理异步错误。</li>
<li>写注释解释“为什么”而不是“是什么”。</li>
</ul>
</div>
</div>
<div class="tip">
🧠 <strong>总结</strong>:JavaScript 是一门灵活但需要严谨对待的语言。理解作用域、异步和数组方法,能让你从“会用”跨越到“精通”。
</div>
</section>
<!-- 页脚 -->
<footer class="footer">
✦ JavaScript 核心笔记 · 持续积累 ✦<br />
多练多写,理解原理,写出健壮的代码。
</footer>
</div>
<!-- end container -->
</body>
</html>
Vue笔记
这是一份为您梳理的 Vue 3 框架核心知识笔记。Vue 3 是当前的主流版本,与 Vue 2 相比,它在性能、开发体验和代码组织上都有了显著的提升。这份笔记将聚焦于 Vue 3 的核心概念与最佳实践,希望能帮助您建立扎实的知识体系。
🌱 一、Vue.js 是什么?
Vue (读音 /vjuː/,类似 view) 是一款用于构建用户界面的 JavaScript 框架。它基于标准 HTML、CSS 和 JavaScript 构建,提供了一套声明式、组件化的编程模型,能帮助我们高效地开发界面。
它的核心优势在于数据驱动和组件化,其核心库只关注视图层,非常易于上手,并能与第三方库或既有项目整合。
🏗️ 二、创建一个 Vue 应用
每个 Vue 应用都是通过 createApp 函数来创建的。
import { createApp } from 'vue'
import App from './App.vue' // 根组件
const app = createApp(App)
app.mount('#app') // 将应用挂载到 DOM 元素上
- 应用实例 (
app):通过createApp返回,用于管理全局资源,如注册组件、指令、插件等。所有全局注册都必须在app.mount()之前完成。 - 根组件 (
App.vue):每个应用都需要一个“根组件”,其他组件将作为其子组件,形成一棵组件树。 - 挂载 (
app.mount()):将应用渲染到页面指定的 DOM 容器中。
🧩 三、核心概念与基础语法
1. 模板语法
Vue 使用基于 HTML 的模板语法,将组件实例的数据声明式地绑定到 DOM 上。
- 插值 (文本):使用
{{ }}语法。html <span>{{ message }}</span> - 指令 (Directives):带有
v-前缀的特殊 attribute,用于在 DOM 上应用响应式行为。v-bind:动态绑定一个或多个 attribute,或一个组件 prop 到表达式。简写为:。html <img :src="imageUrl" />v-model:在表单<input>、<textarea>及<select>元素上创建双向数据绑定。html <input v-model="username" />v-for:基于源数据多次渲染元素或模板块。html <li v-for="item in items" :key="item.id">{{ item.name }}</li>v-if/v-else-if/v-else:条件性地渲染一块内容。html ¨K12Kv-show:通过切换元素的displayCSS 属性来显示/隐藏元素。与v-if不同,v-show不会销毁/重建元素,适用于频繁切换的场景。v-on:绑定事件监听器。简写为@。html <button @click="handleClick">点击我</button>
2. 响应式数据
Vue 3 提供了两种主要方式来声明响应式数据。
ref():用于定义任何类型的响应式数据。在 JavaScript 中访问或修改其值,需要通过.value属性。在模板中会自动“解包”,无需.value。import { ref } from 'vue' const count = ref(0) console.log(count.value) // 0 count.value++reactive():用于定义对象类型(如 Object、Array)的响应式数据。可以直接访问其属性,无需.value。import { reactive } from 'vue' const state = reactive({ count: 0 }) state.count++ // 直接修改注意:reactive()有一些限制,比如不能直接重新赋值整个对象(会丢失响应式),解构时也会丢失响应式。因此,在 Vue 3 的实践中,更推荐使用ref()并结合.value来管理所有状态,这样更统一和可预测。
3. 计算属性 (Computed) 与侦听器 (Watcher)
computed():用于声明计算属性,其值依赖于其他响应式数据,并且具有缓存特性,只有依赖项变化时才会重新计算。import { ref, computed } from 'vue'const firstName = ref('张')const lastName = ref('三')const fullName = computed(() => firstName.value + ' ' + lastName.value)
watch():用于侦听一个或多个响应式数据源,并在数据变化时执行特定的副作用(如异步请求)。import { ref, watch } from 'vue'const question = ref('')watch(question, (newQuestion, oldQuestion) => {// 当 question 变化时,执行一些操作console.log(`问题从 "${oldQuestion}" 变为 "${newQuestion}"`)})
watchEffect():会立即执行传入的函数,并自动追踪其内部所有响应式依赖。当任何依赖发生变化时,该函数会重新运行。import { ref, watchEffect } from 'vue'const count = ref(0)watchEffect(() => {// 立即输出: "count 的值是: 0"console.log(`count 的值是: ${count.value}`)})
🧱 四、组件化开发
组件是 Vue 的核心,它允许我们将 UI 拆分为独立、可复用的部分。
- 父子组件通信
- 父 → 子:通过
props传递数据。 - 子 → 父:通过
$emit触发事件。
- 父 → 子:通过
<script setup>语法糖
这是 Vue 3 中最推荐的组件编写方式,它让组合式 API 的写法更简洁。<template><h1>{{ title }}</h1><button @click="increment">{{ count }}</button></template><script setup>import { ref, defineProps, defineEmits } from 'vue' // 定义 propsconst props = defineProps(['title']) // 定义事件const emit = defineEmits(['update'])const count = ref(0)function increment() {count.value++emit('update', count.value)}</script>
⚙️ 五、组合式 API (Composition API)
这是 Vue 3 最重大的革新,它提供了一种更灵活、更强大的方式来组织和复用组件逻辑。
- 为什么需要它?
- 更好的逻辑复用:可以将相关的逻辑(数据、方法、生命周期等)封装到一个独立的组合式函数 (Composables) 中,并在多个组件间轻松复用。
- 更清晰的代码组织:对于复杂组件,可以按功能(而非选项类型)来组织代码,极大提升了可读性和可维护性。
- 更佳的 TypeScript 支持:组合式 API 基于函数,天然具有优秀的类型推断能力。
- 组合式函数 (Composables) 示例:
- 定义组合式函数:
- // 在useCounter.js文件中
- import { ref } from 'vue'
- /**
- 创建一个包含计数状态及其操作方法的组合式函数
- @param {number} initialValue - 初始计数值,默认为 0
- @returns {Object} 包含 count(ref)、increment、decrement 的对象
*/
export function useCounter(initialValue = 0) {
// 响应式状态
const count = ref(initialValue) // 状态操作函数
const increment = () => {
count.value++
} - const decrement = () => {
count.value--
} // 将状态和操作暴露出去
return {
count,
increment,
decrement
}
} - 在vue组件中使用:
- //CounterComponent.vue
- <template>
- <div>
- <p>当前计数:{{ count }}</p>
- <button @click="increment">增加</button>
- <button @click="decrement">减少</button>
- </div>
- </template>
- <script setup>
- import { useCounter } from './useCounter.js'
- // 使用组合式函数,传入初始值 10
- const { count, increment, decrement } = useCounter(10) </script>
♻️ 六、生命周期钩子 (Lifecycle Hooks)
每个 Vue 组件实例在创建时都会经历一系列初始化步骤——例如,设置数据侦听、编译模板、挂载实例到 DOM、以及在数据变化时更新 DOM 等。在这个过程中,Vue 提供了生命周期钩子,让我们能在特定阶段添加自己的代码。
在组合式 API 中,生命周期钩子以 on 为前缀,并且必须在 setup() 中同步调用。
| 选项式 API (Vue 2 / 3) | 组合式 API (Vue 3) | 描述 |
|---|---|---|
beforeCreate | 直接写在 setup() 中 | 组件实例被创建之初,数据观测和事件配置之前。 |
created | 直接写在 setup() 中 | 组件实例创建完成,属性已绑定,但 DOM 还未生成。 |
beforeMount | onBeforeMount | 在挂载开始之前被调用。 |
mounted | onMounted | 组件被挂载到 DOM 上之后调用,常用于发起异步请求或操作 DOM。 |
beforeUpdate | onBeforeUpdate | 数据更新时调用,发生在虚拟 DOM 打补丁之前。 |
updated | onUpdated | 由于数据更改导致的虚拟 DOM 重新渲染和打补丁之后调用。 |
beforeDestroy (Vue 2) | onBeforeUnmount | 实例销毁之前调用。 |
destroyed (Vue 2) | onUnmounted | 实例销毁后调用。 |
🧭 七、生态与工程化
- 路由 (Vue Router):官方路由管理器,用于构建单页应用 (SPA)。
- 状态管理 (Pinia):Vue 官方推荐的新一代轻量级状态管理库,完美支持组合式 API。
- 构建工具 (Vite):一个由 Vue 作者开发的现代前端构建工具,以其极快的启动和热更新速度著称,是 Vue 3 项目的官方推荐。
Comments NOTHING