# JavaScript 深度指南 ::: tip 前言 你已经学会了 HTML 和 CSS,能做出好看的网页了。但你可能会发现:点击按钮没反应,填了表单提交不了,网页就像一张"静态"的图片。 这就是我们需要 JavaScript 的原因——它让网页"活"起来。点击按钮能弹出菜单,输入文字能实时搜索,滚动页面能加载更多内容……这些交互效果都靠 JavaScript。 在 vibecoding 里,AI 会帮你写大部分代码。但你至少得能看懂代码在做什么,否则 AI 写错了你也发现不了。读完这篇,你就能: - 读懂 AI 写的代码在做什么 - 看出代码哪里有问题 - 用清晰的话告诉 AI 怎么改 ::: **这篇文章会带你学什么?** | 章节 | 内容 | 学完能干嘛 | |-----|------|-----------| | **第 1 章** | JavaScript 是什么 | 明白它在网页里扮演什么角色 | | **第 2 章** | 数据与变量 | 知道程序怎么存东西、怎么用东西 | | **第 3 章** | 函数与逻辑 | 看懂代码的判断、循环和复用逻辑 | | **第 4 章** | DOM 与事件 | 知道代码怎么控制网页、怎么响应用户操作 | | **第 5 章** | 实战技巧 | 拿到 AI 代码怎么读、遇到报错怎么说 | 每一章都从"能识别代码"开始,不需要你会手写。遇到不懂的代码,随时回来查就行。 --- ## 1. JavaScript 是什么 ::: tip 🤔 核心问题 **为什么网页需要 JavaScript?** HTML 和 CSS 已经能让网页有内容、有样式了,为什么还要学一门新语言? ::: ### 1.1 从"静态网页"到"动态应用"
**📄 没有 JavaScript 的网页** - 内容固定,无法交互 - 点击按钮没反应 - 填写表单提交不了 - 页面不会自动更新 *就像一张纸质海报,只能看*
**🚀 有 JavaScript 的网页** - 点击按钮弹出菜单 - 输入文字实时搜索 - 滚动自动加载内容 - 数据实时更新显示 *就像一个真正的应用程序*
**用一句话理解三者的关系:** | 技术 | 比喻 | 作用 | |------|------|------| | **HTML** | 骨架 | 定义网页的结构和内容 | | **CSS** | 皮肤 | 定义网页的外观和样式 | | **JavaScript** | 肌肉和神经系统 | 让网页能响应、能交互、能思考 | ### 1.2 为什么 vibecoding 也需要懂 JavaScript? ::: warning 刚学 JS 的开发者踩坑记 一位刚学 JavaScript 的开发者用 AI 做了一个"计数器"应用:点击按钮,数字加 1。AI 生成的代码能正常工作。 但他想改成"点击加 2",对 AI 说:"让每次点击加 2。" AI 改了代码,可数字还是只加 1。 他问 AI 为啥没效果,AI 解释了一通,但他看不懂代码里的 `count = count + 1` 是什么意思,也不知道 AI 改的是不是这个地方。只能反复说"加 2 没效果",AI 又改了好几版,有的把初始值改成 2,有的在完全不相关的地方加了 2。 最后他看了第 2 章"变量"的概念,明白了 `count = count + 1` 是在把 count 的值加 1 再存回去。然后他对 AI 说:"把 `count + 1` 改成 `count + 2`。" 一次就改对了。 **这就是为什么要懂 JavaScript——不是为了手写代码,而是为了在 AI 没改对时,你能一眼看出问题在哪,一句话说到点子上。** ::: ### 1.3 先睹为快:一段真实的 AI 代码 在深入学习之前,让我们先看一段 AI 生成的真实代码。不要担心看不懂,只要有个印象,后面我们会逐一讲解每个部分。 **场景**:做一个"点击按钮切换背景颜色"的功能 ```javascript // 定义一组颜色 const colors = ['#ff6b6b', '#4ecdc4', '#45b7d1', '#96ceb4'] let currentIndex = 0 // 找到页面上的按钮 const button = document.querySelector('#changeBtn') // 给按钮添加点击事件 button.addEventListener('click', () => { currentIndex = (currentIndex + 1) % colors.length document.body.style.backgroundColor = colors[currentIndex] }) ``` **这段代码在做什么?** | 代码 | 作用 | 对应章节 | |------|------|----------| | `const colors = [...]` | 定义一组颜色数据 | 第 2 章:数组 | | `let currentIndex = 0` | 记录当前显示第几个颜色 | 第 2 章:变量 | | `document.querySelector(...)` | 找到页面上的按钮 | 第 4 章:DOM 查找 | | `button.addEventListener(...)` | 给按钮添加点击事件 | 第 4 章:事件监听 | | `() => {...}` | 定义点击后要执行的代码 | 第 3 章:箭头函数 | ::: info 💡 核心启示 你不需要现在就理解每一行代码。只要记住:**JavaScript 代码就是一系列指令,告诉浏览器"当用户做某事时,应该发生什么"。** ::: --- ## 2. 数据篇:变量与数据类型 ::: tip 🤔 核心问题 **程序是怎么"记住"东西的?** 用户输入的内容、从服务器获取的数据、计算过程中的中间结果——这些信息都存在哪里? ::: ### 2.1 变量:给数据起个名字 **变量就像一个有标签的盒子**——你可以把数据放进去,以后通过标签来取用。 ```javascript const name = "张三" // 名字不会变,用 const let age = 25 // 年龄可能会变,用 let ``` **为什么要区分 const 和 let?** 想象一下:你的身份证号码(const)这辈子都不会变,但你的年龄(let)每年都会变。JavaScript 让你用不同的关键字来表达这种"变与不变"的意图。 | 关键字 | 能否修改 | 使用场景 | 示例 | |--------|---------|----------|------| | `const` | ❌ 不能 | 值不会变的数据 | 身份证号、配置项、颜色列表 | | `let` | ✅ 能 | 值会变化的数据 | 计数器、当前选中的选项、用户输入 | ::: details 🔍 看一个具体的例子 ```javascript // 用 const:这些值不会变 const PI = 3.14159 const MAX_USERS = 100 const APP_NAME = "TodoList" // 用 let:这些值会变化 let count = 0 count = 1 // ✅ 可以修改 count = count + 1 // ✅ 可以基于原值计算 // 如果用 const 会怎样? const fixedCount = 0 fixedCount = 1 // ❌ 报错!const 不能重新赋值 ``` ::: 👇 **动手试试看**:修改下面的代码,看看 const 和 let 的区别 ### 2.2 数据类型:JavaScript 里的几种"东西" JavaScript 把数据分成几种类型,最常用的有三种: | 类型 | 说明 | 示例 | 实际场景 | |------|------|------|----------| | `string`(字符串)| 文本内容 | `"hello"`, `'你好'` | 用户名、商品描述、提示信息 | | `number`(数字)| 数值 | `42`, `3.14` | 价格、数量、评分 | | `boolean`(布尔值)| 是/否 | `true`, `false` | 是否登录、是否完成、是否可见 | **还有两个特殊值需要知道:** - `undefined` → 变量声明了,但还没给值 - `null` → 故意设为空(表示"这里没有值") ::: details 🔍 模板字符串:更方便地拼接文本 在 AI 代码里,你经常会看到用反引号(`` ` ``)包裹的字符串,里面还有 `${...}`: ```javascript const name = "张三" const age = 25 // 传统写法(麻烦) const message = "我叫" + name + ",今年" + age + "岁" // 模板字符串(简洁) const message = `我叫${name},今年${age}岁` // 结果:"我叫张三,今年25岁" ``` **识别要点**:看到反引号和 `${}`,就知道是在把变量插入到文本中。 ::: ### 2.3 对象和数组:把数据组织起来 **对象 = 一组有名字的属性**(像一张个人信息表) ```javascript const user = { name: "张三", age: 25, isVIP: true } // 使用点号访问属性 console.log(user.name) // "张三" console.log(user.age) // 25 ``` **数组 = 一组有顺序的数据**(像一个列表) ```javascript const colors = ['红色', '绿色', '蓝色'] // 用索引访问(从 0 开始) console.log(colors[0]) // "红色" console.log(colors[1]) // "绿色" ``` **嵌套结构:对象里套数组、数组里套对象** 这是 AI 代码中最常见的数据结构: ```javascript const todos = [ { id: 1, text: "学习 JavaScript", done: false }, { id: 2, text: "做项目", done: true }, { id: 3, text: "写文档", done: false } ] // 访问:先取数组的第 0 项,再取它的 text 属性 console.log(todos[0].text) // "学习 JavaScript" ``` ::: info 💡 识别技巧 - 看到 `{}` → 这是一个对象,里面是一组 `名字: 值` - 看到 `[]` → 这是一个数组,里面是一组按顺序排列的值 - 看到 `data[0].name` → 先取数组第 0 项,再取它的 name 属性 ::: ### 2.4 值与引用:一个容易踩的坑 这是新手最常遇到的问题之一! **基本类型(string、number、boolean)赋值 = 复制一份全新的数据:** ```javascript let a = 10 let b = a // b 得到 a 的副本 b = 20 console.log(a) // 10(a 不受影响) ``` **对象和数组赋值 = 复制的是"地址"(指向同一个东西):** ```javascript let user1 = { name: "张三" } let user2 = user1 // user2 指向同一个对象 user2.name = "李四" // 修改 user2 会影响 user1 console.log(user1.name) // "李四"(user1 也变了!) ``` **为什么要创建副本?** 在 React/Vue 中,直接修改数据会导致界面不更新。所以 AI 代码里经常看到 `[...array]` 或 `{...obj}`——它在创建副本,避免互相影响。 ```javascript // 用展开运算符创建副本 const arr1 = [1, 2, 3] const arr2 = [...arr1] // 创建新数组 arr2.push(4) console.log(arr1) // [1, 2, 3](不受影响) console.log(arr2) // [1, 2, 3, 4] ``` 👇 **动手试试看**:观察修改副本时原数据的变化 ### 2.5 解构与展开:现代 JavaScript 的快捷写法 这两个语法在 AI 代码里到处都是,不认识就读不懂代码。 **解构赋值:从对象或数组里快速提取数据** ```javascript const user = { name: "张三", age: 25, city: "北京" } // 传统写法(麻烦) const name = user.name const age = user.age // 解构写法(简洁) const { name, age } = user // 效果一样,但一行搞定 ``` **展开运算符:复制并扩展数据** ```javascript // 复制数组并添加新元素 const arr1 = [1, 2, 3] const arr2 = [...arr1, 4, 5] // [1, 2, 3, 4, 5] // 复制对象并添加新属性 const user1 = { name: "张三", age: 25 } const user2 = { ...user1, city: "北京" } // { name: "张三", age: 25, city: "北京" } ``` ::: info 💡 识别技巧 - 看到 `const { name, age } = person` → 从 person 对象里提取 name 和 age - 看到 `...array` 或 `...obj` → 把数组或对象展开铺平 - 你不需要能手写,但必须能读懂 ::: --- ## 3. 逻辑篇:函数与流程控制 ::: tip 🤔 核心问题 **代码是怎么"做决定"和"重复做事"的?** 程序需要根据条件执行不同的操作,也需要重复执行某些任务——这些逻辑怎么表达? ::: ### 3.1 条件判断:如果...就...否则... **if/else:最基本的条件判断** ```javascript const age = 18 if (age >= 18) { console.log("成年人") } else { console.log("未成年") } ``` **三元运算符:简写的 if/else** ```javascript // 完整写法(4 行) let message if (age >= 18) { message = "成年人" } else { message = "未成年" } // 三元运算符(1 行) const message = age >= 18 ? "成年人" : "未成年" // 格式:条件 ? 条件为真时的值 : 条件为假时的值 ``` **&& 短路写法:React 代码里常见** ```javascript // 只有 isLoggedIn 为 true 时才显示用户面板 isLoggedIn && // 等价于 if (isLoggedIn) { return } ``` ::: info 💡 识别技巧 - 看到 `? :` → 这是三元运算符,简写的 if/else - 看到 `&&` → 前面为 true 才执行后面 ::: ### 3.2 函数:把操作打包起来 **函数 = 一道菜的配方** - 定义函数 = 写下配方 - 调用函数 = 按配方做菜 - 参数 = 原料 - 返回值 = 成品 ```javascript // 定义函数(写下配方) function greet(name) { return "Hello " + name } // 调用函数(按配方做菜) console.log(greet("张三")) // "Hello 张三" console.log(greet("李四")) // "Hello 李四" ``` **三种写法,一眼识别:** ```javascript // 1. function 声明(传统写法) function greet(name) { return "Hello " + name } // 2. 箭头函数(AI 代码里用得最多) const greet = (name) => { return "Hello " + name } // 3. 箭头函数简写(只有一行时) const greet = (name) => "Hello " + name ``` 👇 **动手试试看**:输入不同的名字,看看函数怎么工作 ::: info 💡 识别技巧 - 看到 `function` 或 `=>` → 这是一个函数 - 看到 `fn()` → 在调用这个函数 - 看到 `() => {}` → 箭头函数,现代 JS 的主流写法 ::: ### 3.3 数组方法:处理列表的利器 在 React/Vue 里,几乎每个列表渲染都会用到这些方法。 ```javascript const todos = [ { id: 1, text: "学习", done: false }, { id: 2, text: "工作", done: true } ] // .map():把数组的每一项变成另一个东西 const texts = todos.map(todo => todo.text) // ["学习", "工作"] // .filter():筛选出符合条件的项 const unfinished = todos.filter(todo => !todo.done) // [{ id: 1, text: "学习", done: false }] // .find():找到第一个符合条件的项 const found = todos.find(todo => todo.id === 1) // { id: 1, text: "学习", done: false } ``` ::: info 💡 识别技巧 - 看到 `.map()` → 对数组做变换,返回新数组 - 看到 `.filter()` → 筛选数组 - 看到 `items.map(item =>
  • {item.name}
  • )` → 把每个数据项变成列表标签 ::: ### 3.4 作用域:变量的"可见范围" **用"房间"比喻:** - 函数内部的变量就像房间里的东西,外面看不到 - 但房间里的人可以看到走廊(外层作用域)的东西 ```javascript const global = "全局变量" // 走廊里的东西 function room() { const local = "房间里的东西" // 房间里的东西 console.log(global) // ✅ 能看到走廊 } console.log(local) // ❌ 报错!外面看不到房间里的东西 ``` **核心直觉:** 代码写在哪里,决定了它能看到什么变量。 👇 **动手试试看**:点击不同的作用域,看看能访问哪些变量 ### 3.5 闭包:函数"记住"了它诞生时的环境 **不要把它当成独立的概念,从一个具体场景理解:** ```javascript function setupCounter() { let count = 0 // 这个变量在函数内部 return { add: () => { count++; return count }, getCount: () => count } } const counter = setupCounter() console.log(counter.add()) // 1 console.log(counter.add()) // 2 console.log(counter.getCount()) // 2 ``` **核心直觉:** 函数在被创建时,会"记住"它周围的变量,即使外层函数已经执行完了。 👇 **动手试试看**:观察闭包如何让函数"记住"状态 ### 3.6 this:函数被谁调用 **不讲复杂的绑定规则,只讲最常见的场景:** **场景 1:在对象的方法里,this 指向这个对象** ```javascript const user = { name: "张三", sayHi() { console.log("你好,我是" + this.name) // this 指向 user } } user.sayHi() // "你好,我是张三" ``` **场景 2:在事件监听里,this 指向触发事件的元素** ```javascript button.addEventListener('click', function() { console.log(this) // this 指向 button 元素 }) // 但箭头函数不会改变 this button.addEventListener('click', () => { console.log(this) // this 指向外层的 this }) ``` ::: info 💡 遇到问题怎么办? 如果 AI 代码里出现 this 相关的 bug(比如 `Cannot read property of undefined`),告诉 AI:"这个方法里的 this 指向不对,改成箭头函数或者用 bind" ::: --- ## 4. 交互篇:DOM、事件与异步 ::: tip 🤔 核心问题 **JavaScript 怎么跟网页"互动"?** 怎么找到页面上的元素?怎么响应用户的点击、输入?怎么从服务器获取数据? ::: ### 4.1 DOM:JavaScript 看到的网页 网页在 JavaScript 眼里是一棵"树",每个 HTML 标签都是树上的一个"节点"。 ```html

    标题

    段落

    • 项目1
    • 项目2
    ``` **JS 操控网页 = 找到节点 + 修改节点 + 创建/删除节点** 👇 **动手试试看**:点击节点,看看 DOM 树是怎么组织的 ### 4.2 查找与修改元素 **查找元素:** ```javascript // 根据 CSS 选择器查找(最常用) const title = document.querySelector('h1') // 找第一个 h1 const button = document.querySelector('#btn') // 找 id="btn" 的元素 const items = document.querySelectorAll('.item') // 找所有 class="item" 的元素 ``` **修改元素:** ```javascript // 改文字 title.textContent = "新标题" // 改样式 element.style.color = "red" element.style.fontSize = "20px" // 改 CSS 类 element.classList.add('active') // 添加类 element.classList.remove('hidden') // 移除类 element.classList.toggle('open') // 切换类(有就移除,没有就添加) ``` ::: info 💡 识别技巧 - 看到 `document.querySelector` → 在查找网页元素 - 看到 `.textContent` → 改文字 - 看到 `.style.xxx` → 改样式 - 看到 `.classList.add/remove/toggle` → 改 CSS 类 ::: ### 4.3 事件:当用户做了某个操作时... **addEventListener:给元素添加事件监听** ```javascript button.addEventListener('click', () => { console.log("按钮被点击了") }) ``` **常见事件:** | 事件 | 触发时机 | 实际场景 | |------|---------|----------| | `click` | 点击 | 按钮点击、链接跳转 | | `input` | 输入框内容变化 | 实时搜索、表单验证 | | `submit` | 表单提交 | 登录、注册、提交数据 | | `scroll` | 滚动页面 | 懒加载、回到顶部 | **事件对象:获取更多信息** ```javascript input.addEventListener('input', (e) => { console.log(e.target.value) // 获取输入框的值 e.preventDefault() // 阻止默认行为(比如表单提交后刷新页面) }) ``` ::: info 💡 实际应用 当你想给按钮加一个功能,本质上就是在告诉 AI:"给这个按钮添加一个点击事件,点击后执行某某操作" ::: ### 4.4 异步:为什么有些操作不是立刻完成的 **餐厅比喻:** 点菜后不用站在厨房门口等,可以先做别的事,菜好了服务员会端过来。 **最常见场景:从服务器获取数据** ```javascript // 同步写法(会卡住页面,不要用) const data = fetch('/api/data') // ❌ 这样写会卡住 // 异步写法(正确) async function loadData() { try { const response = await fetch('/api/data') const data = await response.json() console.log(data) } catch (error) { console.error('出错了:', error) } } ``` **async/await 语法:** - `async` → 标记这个函数里有异步操作 - `await` → 等待这个操作完成(但不会卡住页面) - `try/catch` → 处理可能出现的错误 👇 **动手试试看**:观察异步操作的执行顺序 ::: info 💡 识别技巧 - 看到 `async/await` → 在等待耗时操作 - 看到 `fetch()` → 在从服务器获取数据 - 看到 `try/catch` → 在处理可能的错误 ::: ### 4.5 事件循环:JavaScript 到底怎么工作的 **不用术语"微任务/宏任务",用一个简单的模型理解:** **JS 是一个"单人工位"**,同时只做一件事,但有一个"待办便签栏"(任务队列)。 当遇到要等待的操作(网络请求、定时器),JS 不是傻等,而是把"等好了之后做什么"贴到便签栏,自己继续往下执行。等当前事情做完了,才去看便签栏。 ```javascript console.log("1") setTimeout(() => console.log("2"), 0) // 即使是 0 秒,也会推迟 console.log("3") // 输出:1, 3, 2(不是 1, 2, 3!) ``` **为什么?** 1. 执行 `console.log("1")` → 输出 1 2. 遇到 `setTimeout` → 把回调贴到便签栏,继续往下 3. 执行 `console.log("3")` → 输出 3 4. 当前代码执行完了,去看便签栏 5. 执行 `setTimeout` 的回调 → 输出 2 👇 **动手试试看**:观察代码的执行顺序 ::: info 💡 遇到问题怎么办? 如果 AI 代码里数据还没获取到页面就渲染了,告诉 AI:"数据还没加载完就开始渲染了,需要添加 loading 状态,等数据到了再渲染" ::: ### 4.6 模块:import 和 export AI 生成的 React/Vue 代码第一行几乎都是 `import`。 **import = 从别的文件引入功能** ```javascript // 从工具文件引入函数 import { formatDate } from './utils' // 从第三方包引入 import React from 'react' import { useState } from 'react' ``` **export = 把功能暴露出去给别人用** ```javascript // utils.js export function formatDate(date) { // ... } // 或者默认导出 export default function formatDate(date) { // ... } ``` **npm 包 = 别人写好的工具,安装后就能用** ```javascript // 安装包:npm install lodash // 使用包 import _ from 'lodash' ``` ::: info 💡 识别技巧 - 看到 `import` → 从别的文件引入功能 - 看到 `export` → 把功能暴露给别人用 - 看到 `from 'react'` → 从 React 包引入 - 看到 `from './utils'` → 从本地文件引入 ::: --- ## 5. 实战篇:读懂代码、看懂报错、精准描述 ::: tip 🤔 核心问题 **前面学了这么多语法,实际拿到 AI 代码时怎么用?** 怎么快速读懂代码?遇到报错怎么办?怎么让 AI 准确地帮你改代码? ::: ### 5.1 拿到 AI 代码后怎么读 **四步法:** | 步骤 | 看什么 | 示例 | |------|--------|------| | **第一步:看整体结构** | 有几个函数?分别做什么? | `loadData()` 加载数据,`renderList()` 渲染列表 | | **第二步:找入口** | 程序从哪里开始执行? | `addEventListener('click', ...)` 点击时开始 | | **第三步:追踪数据流** | 数据从哪里来?到哪里去? | 从 API 获取 → 解析 → 渲染到页面 | | **第四步:看细节逻辑** | 具体函数里怎么处理的? | 循环、判断、计算 | **用第 1 章的代码示例做一次完整的"阅读演示":** ```javascript // 第一步:整体结构 // - 一个颜色数组 // - 一个变量记录当前索引 // - 一个按钮的点击事件 // 第二步:入口点 // button.addEventListener('click', ...) → 点击按钮时执行 // 第三步:数据流 // colors(颜色数组)→ currentIndex(当前索引)→ backgroundColor(背景色) // 第四步:细节逻辑 // currentIndex = (currentIndex + 1) % colors.length // 这个公式的意思:每次 +1,但不超过数组长度(循环) ``` ### 5.2 常见报错速查 | 报错 | 大白话解释 | 怎么跟 AI 说 | |------|-----------|-------------| | `TypeError: Cannot read properties of undefined` | 你想从一个不存在的东西上取值 | "第 X 行报错,某某变量是 undefined,检查它的赋值逻辑" | | `ReferenceError: xxx is not defined` | 用了一个没有声明过的变量名 | "变量 xxx 没有定义,是不是拼写错了或者忘了导入" | | `TypeError: xxx is not a function` | 把一个不是函数的东西当函数调用了 | "xxx 不是函数,检查一下它的类型和来源" | | `SyntaxError: Unexpected token` | 语法写错了(括号不匹配、少了逗号等) | "第 X 行语法错误,检查括号和标点" | | `CORS error` | 浏览器阻止了跨域请求 | "遇到 CORS 错误,需要配置跨域资源共享" | | `404 Not Found` | 请求的资源不存在 | "API 返回 404,检查接口地址是否正确" | ### 5.3 如何精准描述问题 新手和熟练开发者的差距,往往就体现在**描述问题的精准度**上。 | ❌ 差的描述 | ✅ 好的描述 | |-----------|-----------| | "代码有 bug" | "点击删除按钮时,删除的不是当前项而是最后一项" | | "样式不对" | "标题应该居中,现在是左对齐" | | "数据显示不出来" | "fetch 请求返回了数据(控制台能看到),但页面没有重新渲染" | | "加一个功能" | "在用户列表页面添加一个搜索框,输入时实时过滤列表,按 name 字段模糊匹配" | | "点击没反应" | "点击按钮时控制台报错 'Cannot read property of undefined',错误在第 X 行" | **一个实战练习:** ```javascript // 有 bug 的代码 function deleteTodo(index) { todos.splice(index, 1) // 总是删除最后一项 } // 错误现象:无论点哪个删除按钮,删的都是最后一项 ``` **❌ 差的描述:** "删除功能有 bug" **✅ 好的描述:** "点击删除按钮时,删除的不是当前项而是最后一项。代码里用了 splice(index, 1),但 index 可能不正确。需要改成用每个事项的唯一 id 来匹配删除。" ### 5.4 你现在应该能识别的代码 - 看到 `const/let` → 知道变量能不能重新赋值 - 看到 `{}` → 对象 / 看到 `[]` → 数组 - 看到 `{...obj}` 或 `[...arr]` → 在创建副本 - 看到 `function` 或 `=>` → 定义了一段可重复执行的操作 - 看到 `if/else` 或 `? :` → 代码在做判断 - 看到 `.map()` / `.filter()` → 在变换或筛选数组 - 看到 `document.querySelector` → 在查找网页元素 - 看到 `addEventListener` → 在监听用户操作 - 看到 `async/await` → 在等待耗时操作 - 看到 `import/export` → 在引入或导出模块 - 遇到报错 → 能读懂大意并精准描述给 AI **如果你认真读了每章的"深入"部分,你还掌握了这些核心概念:** - **值 vs 引用**:基本类型复制值,对象/数组复制的是地址 - **作用域与闭包**:函数能"记住"它诞生时周围的变量 - **this 的本质**:取决于函数被谁调用,而不是写在哪里 - **事件循环**:JS 是单线程的,靠任务队列实现"不阻塞" 这些概念会帮你更快定位问题。 ::: info 💡 遇到问题时这样跟 AI 说 - "第 X 行报错 XXX,帮我看看是什么问题" - "这个函数的逻辑是 XXX,但结果不对,应该是 XXX" - "我想修改 XXX 功能,具体要求是 XXX" :::