掌握 JavaScript 基础是前端工程师的必备素养,不仅是日常开发的核心支撑,更是向中高级岗位进阶的关键基石。以下梳理了面试高频考察点,结合核心原理与实战案例,助力高效备战面试。
Taimili 艾米莉 ( 一款专业的 GitHub star 管理和github 加星涨星工具taimili.com )
艾米莉 是一款优雅便捷的 GitHub star 管理和github 加星涨星工具,基于 PHP & javascript 构建, 能对github 得 star fork follow watch 管理和提升,最适合github 的深度用户
一、数据类型与内存机制
1. 基本数据类型
包含 String、Number、Boolean、Null、Undefined、ES6 新增的 Symbol(唯一值)、ES2020 新增的 BigInt(大整数)。
- 存储位置:栈内存(Stack)
- 核心特性:变量直接持有值,赋值操作是值的复制,修改新变量不影响原变量。
2. 引用数据类型
以 Object 为基础,涵盖普通对象、Array、Function、Date 等。
- 存储机制:对象实体存于堆内存(Heap),变量仅持有指向堆内存的引用地址(引用存于栈内存)
- 核心特性:赋值操作是引用的复制,多个变量可能指向同一对象,修改任一变量的属性会影响所有关联变量。
3. 经典面试案例
javascript
运行
// 基本类型赋值:值复制,互不影响
let a = 10;
let b = a;
b = 20;
console.log(a); // 输出:10
// 引用类型赋值:引用复制,指向同一对象
let obj1 = { name: 'Mickey' };
let obj2 = obj1;
obj2.name = 'Donald';
console.log(obj1.name); // 输出:Donald
4. 类型判断方法
| 方法 | 适用场景 | 局限性 |
|---|---|---|
typeof | 快速判断基本类型 | 1. typeof null 返回 object(历史遗留);2. 无法区分对象子类型(如 Array、Date) |
instanceof | 判断对象是否为构造函数实例 | 基于原型链查找,Array 实例同时属于 Object |
javascript
运行
console.log(typeof []); // "object"(无法识别数组)
console.log([1,2,3] instanceof Array); // true(正确识别数组)
二、变量声明:var、let 与 const(ES6 必考点)
三者核心差异是面试高频题,需精准掌握作用域、提升机制等关键特性:
| 特性 | var | let | const |
|---|---|---|---|
| 作用域 | 函数作用域 | 块级作用域({} 包裹) | 块级作用域({} 包裹) |
| 变量提升 | 存在(仅声明提升) | 无(存在暂时性死区 TDZ) | 无(存在暂时性死区 TDZ) |
| 重复声明 | 允许 | 不允许 | 不允许 |
| 重新赋值 | 允许 | 允许 | 不允许(引用不可变) |
关键考点解析
- 暂时性死区(TDZ):
let/const声明前访问变量会抛出 ReferenceError,避免变量提前使用 const的 "不变性":仅保证引用地址不变,对象 / 数组的内部属性可修改
javascript
运行
const person = { age: 30 };
person.age = 31; // 允许,修改内部属性
// person = {}; // 报错,禁止修改引用地址
三、运算符(重点掌握短路特性)
1. 核心运算符分类
- 算术运算符:
+、-、*、/、%(取模)、**(ES7 幂运算) - 比较运算符:
==(类型转换后比较)、===(严格相等,推荐使用) - 逻辑运算符:
&&(与)、||(或)(均支持短路求值) - 三元运算符:
condition ? 真结果 : 假结果(简洁替代简单 if-else)
2. 短路特性实战(开发高频用法)
javascript
运行
// && 短路:第一个假值直接返回,后续不执行
const userName = user && user.name; // 安全访问嵌套属性,避免报错
const result1 = 0 && console.log('不会执行'); // 输出:0
// || 短路:第一个真值直接返回,后续不执行
function greet(name) {
name = name || 'Guest'; // ES6前的默认参数方案
console.log(`Welcome, ${name}`);
}
greet(); // 输出:Welcome, Guest
四、流程控制
1. 条件语句
if...else if...else:处理多条件判断switch:单值多分支场景,需注意break防止穿透
javascript
运行
function getFruitColor(fruit) {
switch (fruit) {
case 'apple': return 'red';
case 'banana': return 'yellow';
default: return 'unknown';
}
}
2. 循环语句
| 循环类型 | 适用场景 | 特点 |
|---|---|---|
for | 已知循环次数 | 灵活控制索引 |
while | 未知循环次数,条件前置 | 条件不满足则不执行 |
do...while | 未知循环次数,条件后置 | 至少执行一次 |
for...of | 遍历可迭代对象(数组、字符串等) | 直接获取值,语法简洁 |
javascript
运行
const numbers = [10, 20, 30];
// for...of 遍历(推荐)
for (const num of numbers) {
console.log(num); // 输出:10、20、30
}
五、函数(JavaScript 一等公民)
1. 三种声明方式对比
| 声明方式 | 语法示例 | 核心特性 |
|---|---|---|
| 函数声明 | function sum(a,b) { return a+b } | 存在函数提升,可在声明前调用 |
| 函数表达式 | const multiply = function(a,b){} | 遵循变量提升规则,声明前不可调用 |
| 箭头函数(ES6) | const subtract = (a,b) => a-b | 语法简洁,this 绑定词法作用域 |
2. 面试高频考点:函数提升
javascript
运行
console.log(declaredSum(2,3)); // 输出:5(函数声明提升)
function declaredSum(a,b) { return a+b; }
// console.log(expressedSum(2,3)); // 报错(函数表达式无提升)
const expressedSum = function(a,b) { return a+b; };
六、对象操作
1. 核心操作方法
-
创建:
const obj = { key: 'value' }(字面量语法,推荐) -
属性访问:
- 点表示法:
obj.key(属性名是合法标识符时使用) - 方括号表示法:
obj['key'](支持特殊字符、动态属性名)
- 点表示法:
-
增删改:
obj.newKey = 'newVal'(增 / 改)、delete obj.key(删)
2. 遍历技巧(避免原型链污染)
javascript
运行
const car = { make: 'Toyota', model: 'Camry', 'year-2022': true };
// for...in 遍历,仅获取自身属性
for (const key in car) {
if (car.hasOwnProperty(key)) {
console.log(`${key}: ${car[key]}`);
}
}
七、数组(高频操作与方法)
1. 核心特性
- 访问:通过索引
arr[index],索引从 0 开始 length:可读写属性,用于获取长度或截断数组
2. 常用方法分类(面试重点)
| 类型 | 方法 | 特点 |
|---|---|---|
| 改变原数组 | push/pop、unshift/shift、splice、sort | 直接修改原数组,需注意副作用 |
| 不改变原数组 | concat、slice、map、filter、find | 返回新数组,原数组保持不变(推荐使用) |
3. 经典面试对比:map vs forEach
javascript
运行
const ids = [1, 2, 3];
// forEach:仅遍历,无返回值
ids.forEach(id => console.log(`处理ID:${id}`));
// map:映射转换,返回新数组(核心用途)
const urls = ids.map(id => `/users/${id}`);
console.log(urls); // 输出:['/users/1', '/users/2', '/users/3']
八、DOM 操作与事件模型
1. 高效 DOM 操作(性能优化考点)
大量添加节点时,使用 DocumentFragment 减少重排(reflow)和重绘(repaint):
javascript
运行
const list = document.getElementById('my-list');
const fragment = document.createDocumentFragment(); // 临时容器
// 先添加到片段(无DOM重排)
for (let i = 0; i < 1000; i++) {
const li = document.createElement('li');
li.textContent = `Item ${i+1}`;
fragment.appendChild(li);
}
// 一次性插入DOM(仅1次重排)
list.appendChild(fragment);
2. 事件委托(性能优化 + 动态元素适配)
利用事件冒泡机制,将监听器绑定到父元素,统一处理子元素事件:
html
预览
<ul id="parent-list">
<li>Item 1</li>
<li>Item 2</li>
</ul>
javascript
运行
const parent = document.getElementById('parent-list');
parent.addEventListener('click', (e) => {
// 精准匹配目标元素
if (e.target.nodeName === 'LI') {
console.log(`点击了:${e.target.textContent}`);
}
});
九、AJAX 与本地存储
1. fetch API(主流异步请求方案)
基于 Promise,需手动处理 HTTP 错误状态码:
javascript
运行
async function fetchUserData() {
try {
const res = await fetch('https://api.example.com/user/1');
if (!res.ok) throw new Error(`HTTP错误:${res.status}`); // 处理404/500等错误
const data = await res.json(); // 解析JSON响应
console.log(data);
} catch (err) {
console.error('请求失败:', err);
}
}
2. 本地存储方案对比(面试高频)
| 方案 | 生命周期 | 存储大小 | 与服务器通信 |
|---|---|---|---|
| localStorage | 永久存储,手动清除 | 约 5MB | 不携带,仅客户端使用 |
| sessionStorage | 标签页关闭后清除 | 约 5MB | 不携带,仅客户端使用 |
| Cookie | 可设置过期时间(默认会话) | 约 4KB | 每次 HTTP 请求自动携带 |