⭐ JavaScript 精讲速查

重点精简 · 交互式要点 · 适合快速上手

1. 变量声明

let / const / var 的区别是面试必考题
关键字作用域可重新赋值用途
var函数级(会变量提升)可以旧代码,现在少用
let块级 {}可以✅ 推荐:会变的量
const块级 {}不可以(指向不变)✅ 推荐:不变/对象
// 命名规则:camelCase 驼峰式
let count = 0;
count = 1;            // ✅ 可改

const PI = 3.14;
PI = 3;               // ❌ 报错:不能重新赋值

// 但 const 对象内部属性可以改
const user = { name: 'Tom' };
user.name = 'Jerry';  // ✅ 合法,改的是属性
要点:默认都用 const,需要更改变量值时再用 let。避免使用 var

2. 数据类型(8 种)

7 种原始类型 + 1 种引用类型
类型说明示例
number整数和浮点都用它42 3.14 NaN
string字符串(' ' 或 " " 或 ` `)'hi'
boolean布尔true false
undefined声明但未赋值let a;
null手动置空let a = null
bigint大整数10n
symbol唯一值Symbol('x')
object引用类型(含数组、函数){} []
typeof 42;      // "number"
typeof 'x';      // "string"
typeof [];       // "object"(数组也是对象)
typeof null;    // "object"(JS 历史遗留 bug)
typeof function(){}; // "function"
常见坑:undefined == nulltrue,但 ===false判断空值用 == null,两者都捕获。

3. 运算符

重点掌握「严格相等」和「模板字符串」

相等比较(最重要的区别)

1 == '1';   // true  (== 会做类型转换)
1 === '1';  // false (=== 严格,不转换)✅ 推荐

逻辑 / 三元运算

const age = 20;
// 三元:条件 ? 真 : 假
const label = age >= 18 ? '成年' : '未成年';

// ?? 空值合并:null/undefined 时才用默认值(0、'' 不会)
const n = 0 ?? 10;  // 0 (0 有效值)
// 而 || 只要「假值」就用默认值
const m = 0 || 10;  // 10

模板字符串

const name = 'Tom';
console.log(`Hello, ${name}! 你有 ${18+2} 岁。`);
// 用反引号 `,插入变量用 ${...}

4. 流程控制

if / switch 条件

if (score >= 90) {
  'A';
} else if (score >= 60) {
  'B';
} else {
  'C';
}

switch (day) {
  case 1: '周一'; break;
  case 2: '周二'; break;
  default: '其他';
}

循环:for / while / for...of

for (let i=0; i<3; i++) { /* 3 次 */ }

while (cond) { /* 条件为真则循环 */ }

// ✅ 最常用:遍历数组元素
for (const item of arr) { /* 每次得到元素 */ }
要点:遍历数组首选 for...of;遍历对象属性用 for...in(少用)。

5. 函数

四种写法,理解 this 与箭头函数

四种声明方式

// 1. 函数声明(会提升)
function add(a, b) { return a + b; }

// 2. 函数表达式
const add2 = function(a, b) { return a + b; };

// 3. 箭头函数(更简洁,推荐)✅
const add3 = (a, b) => a + b;
// 单参数可省略括号
const double = x => x * 2;

// 4. 立即执行函数 IIFE
(function(x){ console.log(x); })(5);
关键区别:this
箭头函数没有自己的 this,会继承外面作用域的 this
普通函数 this 取决于调用方式。回调场景优先用箭头函数避免 this 丢失。

6. 数组 & 常用方法

map / filter / reduce 是重点中的重点
const nums = [1, 2, 3, 4];

// map:每个元素变换成长度相等的新数组
const doubled = nums.map(n => n * 2); // [2,4,6,8]

// filter:筛选出满足条件的
const even = nums.filter(n => n % 2 === 0); // [2,4]

// reduce:累加/归约为单个值
const sum = nums.reduce((acc, n) => acc + n, 0); // 10

// 其他常用
nums.push(5);        // 末尾加
nums.pop();          // 末尾删
arr.indexOf(x);      // 查找下标,无返回 -1
arr.includes(x);     // 是否存在 → true/false
arr.slice(1,3);    // 截取(不改原数组)
要点: - map / filter / includes / find 返回新值不清脆地改原数组(不可变)。 - push / pop / sort / splice修改原数组(可变)。

7. 对象

键值对,访问与解构
const user = {
  name: 'Tom',
  age: 20,
  greet(){ 'hi ' + this.name; }   // 简写方法
};

// 访问两种方式
user.name;      // 点号
user['age'];    // 中括号(变量作键时要用)

// ✅ 解构赋值(超常用)
const { name, age } = user;  // 取出 name, age

// 展开运算
const clone = { ...user };  // 浅拷贝
对象是引用类型:赋值传递的是地址。复制给另一个变量后改一个,两个都变。用 {...obj} 做浅拷贝。

8. 字符串常用方法

'Hello'.length;          // 5
'Hello'[0];             // 'H'
'a,b,c'.split(',');    // ['a','b','c']
['a','b'].join('-');  // 'a-b'
' Hello '.trim();       // 'Hello'
'hello'.toUpperCase();  // 'HELLO'
'abc'.includes('b'); // true
'Hello'.replace('l','L'); // 'HeLlo'(只换第一个)

9. DOM 与事件(详细篇)

操作网页元素 + 监听用户交互 —— 前端开发的"手脚"

9.1 什么是 DOM

DOM(Document Object Model):把 HTML 页面抽象成一颗「节点树」。浏览器把每个标签变成一个 JS 对象,JS 就能用这些对象改写页面。只要页面一打开,document 就代表整份文档。

// 页面结构(HTML)
<div id="app">
    <h1>标题</h1>
    <button id="btn">点我</button>
</div>

// 对应 DOM 树:document → div#app → (h1, button)
// JS 通过 document 一层层拿到元素对象

9.2 选择元素(重中之重)

方法作用返回推荐度
getElementById('id')按 id 找单个元素
getElementsByClassName('cls')按类名找类数组(HTMLCollection)一般
getElementsByTagName('li')按标签找类数组一般
querySelector('div .cls')CSS选择器,找第一个单个元素或null✅✅ 首选
querySelectorAll('.cls')CSS选择器,所有NodeList(可forEach)✅✅ 首选
const box = document.getElementById('box');      // 按 id
const active = document.querySelector('.active'); // 第一个匹配,没有→null
const allLi = document.querySelectorAll('ul li');  // 全部,可用 forEach

allLi.forEach(li => console.log(li.textContent)); // NodeList 支持 forEach ✅
推荐:一律用 querySelector / querySelectorAll,一套 CSS 选择器语法通吃,比 getElementById 系列更灵活。

9.3 修改内容 / 属性 / 样式 / 类名

// ① 内容
el.textContent = '纯文本';        // 显示为普通文字(安全)
el.innerHTML  = '<b>加粗</b>';   // 解析成 HTML(慎重,防XSS)

// ② 属性
el.href = 'https://ex.com';      // 改链接
el.src  = 'img.png';           // 改图片
el.setAttribute('title', '提示'); // 设任意属性
el.value = '输入框的值';          // 表单取值/赋值

// ③ 样式(内联风格)
el.style.color = 'red';
el.style.fontSize = '20px';   // CSS 请转驼峰:font-size→fontSize

// ④ 类名(d lassList 操作最佳)
el.classList.add('active');
el.classList.remove('active');
el.classList.toggle('active');  // 有就删、没有就加(做开关超好用)
el.classList.contains('active'); // 是否包含 → true/false

9.4 创建 / 添加 / 删除元素

// 新建元素 → 插入某处 → 删除
const li = document.createElement('li');
li.textContent = '新增项';

const ul = document.querySelector('ul');
ul.appendChild(li);       // 加到最后
ul.prepend(li);            // 加到最前
ul.appendChild(li);        // 若 li 已存在,会【移动】而非复制

li.remove();               // 直接删除元素(现代写法)
ul.removeChild(li);        // 传统写法:指定子元素

// 整块插入(模板字符串 + 配合字符串按钮)
ul.innerHTML += '<li>新内容</li>'; // ⚠️会重建整个里面所有内容,永别用做绑定事件
注意:innerHTML += 会把整个元素重新解析一遍,里面已绑的事件会丢。给动态列表加项,用 createElement 更稳。

9.5 事件监听:三种写法

写法代码评价
① HTML 属性(旧)<button onclick="fn()">❌ 不推荐,HTML 和 JS 混一起
② 属性赋值btn.onclick = fn只能绑一个,晚绑的覆盖
③ addEventListener ✅btn.addEventListener('click', fn)✅ 可同时绑多个,推荐
const btn = document.querySelector('#btn');
btn.addEventListener('click', function(e){
  console.log('第一次点击');
});
btn.addEventListener('click', function(e){
  console.log('第二次点击(都执行)');
});
// 移除监听要引同一函数引用
btn.removeEventListener('click', fn);

9.6 常用事件分类

类型事件触发时机
鼠标click dblclick mouseover mouseout mouseenter mousemove点击/悬停/移动
键盘keydown keyup按下/松开按键
表单input change submit focus blur输入、变化、提交、聚焦、失焦
窗口/文档load DOMContentLoaded resize scroll加载完成、窗口大小、滚动
点睛:DOMContentLoaded 在 DOM 结构就绪就触发(不用等图片),常用它包住初始化代码,保证元素已存在。input 每敲一字都触发,做搜索实时过滤神器。

9.7 事件对象 event

监听函数的第一个参数就是事件对象,里面装了大量事件细节。
btn.addEventListener('click', function(e){
  e.target;        // 实际被点到的元素(用于事件委托)
  e.currentTarget; // 绑监听的那个元素
  e.preventDefault(); // 阻止默认行为(如跳转、提交表单刷新)
  e.stopPropagation(); // 阻止事件冒泡向上传播
});

9.8 事件冒泡 vs 捕获 + 事件委托(重点)

事件冒泡(默认):从一个元素触发后,会逐级向上传递到父级,直到 document。利用这一点,可以只给父级绑一次事件,用 e.target 判断点到了谁 —— 这叫事件委托,对动态新增元素特别有用。
// 事件委托:给 ul 绑一次监听,管住所有 li(包括以后新增的)
const ul = document.querySelector('ul');
ul.addEventListener('click', function(e){
  if(e.target.tagName === 'LI'){        // 判断点的是不是 li
    console.log('点击了: ' + e.target.textContent);
  }
});
// 之后新加的 li 也自动有响应,不用再单独绑 ✅
为什么要委托:新增元素你没办法挨个绑;且委托只需一个监听器,性能更好。手机列表、动态渲染的长列表大量用它。

9. 异步编程

Promise / async / await 是现代 JS 核心难点

Promise 基础

const p = new Promise((resolve, reject) => {
  setTimeout(() => resolve('成功'), 1000);
  // 失败时: reject(new Error('失败了'))
});

p.then(msg => console.log(msg))   // 成功回调
 .catch(err => console.log(err));  // 失败回调

async / await(推荐写法 ✅)

async function fetchData() {
  try {
    const res = await fetch('https://api.example.com');
    const data = await res.json();
    return data;
  } catch (err) {
    console.log('出错:', err);
  }
}
要点: - async 函数内用 await 等待 Promise,代码像同步一样直观。 - 用 try / catch 抓错误。 - 线程安全:JS 是单线程,异步靠事件循环(Event Loop)实现。

10. ES6+ 常用新特性

现代开发每天都在用
// 可选链 & 空值合并(省去很多 if)
const name = user?.profile?.name ?? '匿名';

// 数组复制与合并
const a = [1], b = [2, ...a];  // b = [2,1]

// 对象展开浅拷贝
const copy = { ...; }; 

11. 动手实验

点击按钮运行效果
(未运行)
// 尝试修改下面的代码,看看 map / filter / reduce
const data = [1, 2, 3, 4, 5];
const result = data
  .filter(n => n % 2 === 1)        // 取奇数
  .map(n => n * 10)                 // 乘 10
  .reduce((sum, n) => sum + n, 0);  // 求和

document.getElementById('out').textContent = '结果 = ' + result;