JavaScript面试题精讲:从基础到高级的全面覆盖
本文深入解析JavaScript从ES6+新特性到核心概念的全面知识体系,涵盖块级作用域、箭头函数、Promise异步编程、async/await、模块化系统等现代JavaScript核心特性,同时深度剖析原型链与闭包机制,并提供手写代码的实现技巧和实战示例。内容从基础到高级全面覆盖,帮助开发者系统掌握JavaScript面试必备知识点,提升编程能力和面试通过率。
ES6+新特性深度解析
随着JavaScript语言的快速发展,ES6(ECMAScript 2015)及后续版本带来了革命性的新特性,这些特性不仅提升了开发效率,更从根本上改变了JavaScript的编程范式。本文将深入解析ES6+的核心特性,帮助开发者全面掌握现代JavaScript开发的核心技能。
块级作用域:let与const的革命
ES6引入的let和const关键字彻底改变了JavaScript的作用域机制,解决了var声明带来的变量提升和全局污染问题。
// 传统的var声明存在的问题
function varExample() {
console.log(i); // undefined,变量提升
for (var i = 0; i < 3; i++) {
setTimeout(() => console.log(i), 100); // 输出3次3
}
}
// 使用let的块级作用域
function letExample() {
for (let i = 0; i < 3; i++) {
setTimeout(() => console.log(i), 100); // 输出0,1,2
}
}
// const声明常量
const PI = 3.14159;
// PI = 3.14; // TypeError: Assignment to constant variable
// const对于对象和数组
const obj = { name: 'John' };
obj.name = 'Jane'; // 允许修改属性
obj = {}; // TypeError: Assignment to constant variable
作用域对比表:
| 特性 | var | let | const |
|---|---|---|---|
| 作用域 | 函数作用域 | 块级作用域 | 块级作用域 |
| 变量提升 | 是 | 否(暂时性死区) | 否(暂时性死区) |
| 重复声明 | 允许 | 不允许 | 不允许 |
| 初始值要求 | 可选 | 可选 | 必须 |
| 重新赋值 | 允许 | 允许 | 不允许 |
箭头函数:简洁的语法与this绑定
箭头函数不仅提供了更简洁的语法,更重要的是解决了传统函数中this指向的困惑问题。
// 传统函数
const numbers = [1, 2, 3, 4, 5];
const squares = numbers.map(function(n) {
return n * n;
});
// 箭头函数简化
const squaresArrow = numbers.map(n => n * n);
// this绑定差异
const obj = {
name: 'Object',
traditionalFunction: function() {
console.log(this.name); // Object
},
arrowFunction: () => {
console.log(this.name); // undefined(指向外层作用域)
}
};
// 多层嵌套的简洁性
const complexOperation = data =>
data
.filter(item => item.active)
.map(item => ({
...item,
fullName: `${item.firstName} ${item.lastName}`
}))
.sort((a, b) => a.age - b.age);
箭头函数特性总结:
- 没有自己的
this,继承外层函数的this值 - 不能用作构造函数,不能使用
new关键字 - 没有
arguments对象,可以使用rest参数替代 - 不能使用
yield关键字,不能用作Generator函数
Promise与异步编程革命
Promise对象为JavaScript异步编程提供了标准化的解决方案,解决了回调地狱问题。
// 回调地狱示例
function callbackHell() {
getUser(userId, function(user) {
getPosts(user.id, function(posts) {
getComments(posts[0].id, function(comments) {
console.log(comments);
});
});
});
}
// Promise链式调用
function promiseChain() {
getUser(userId)
.then(user => getPosts(user.id))
.then(posts => getComments(posts[0].id))
.then(comments => console.log(comments))
.catch(error => console.error('Error:', error));
}
// Promise静态方法
const promises = [
fetch('/api/users'),
fetch('/api/posts'),
fetch('/api/comments')
];
Promise.all(promises)
.then(responses => Promise.all(responses.map(r => r.json())))
.then(data => {
const [users, posts, comments] = data;
console.log('All data loaded:', { users, posts, comments });
});
Promise.race(promises)
.then(response => console.log('First response:', response));
Promise状态转换流程图:
async/await:同步风格的异步编程
async/await基于Promise构建,让异步代码看起来像同步代码一样直观。
// 传统Promise写法
function fetchData() {
return fetch('/api/data')
.then(response => response.json())
.then(data => processData(data))
.catch(error => handleError(error));
}
// async/await写法
async function fetchDataAsync() {
try {
const response = await fetch('/api/data');
const data = await response.json();
const processedData = await processData(data);
return processedData;
} catch (error) {
handleError(error);
}
}
// 并行请求优化
async function fetchMultipleData() {
const [userData, postData, commentData] = await Promise.all([
fetch('/api/users').then(r => r.json()),
fetch('/api/posts').then(r => r.json()),
fetch('/api/comments').then(r => r.json())
]);
return { userData, postData, commentData };
}
// 错误处理模式
async function robustFetch() {
try {
const result = await someAsyncOperation();
return { success: true, data: result };
} catch (error) {
console.error('Operation failed:', error);
return { success: false, error: error.message };
}
}
模块化系统:import与export
ES6模块系统提供了官方的模块化解决方案,取代了之前的CommonJS和AMD等方案。
// math.js - 命名导出
export const PI = 3.14159;
export function square(x) {
return x * x;
}
export function cube(x) {
return x * x * x;
}
// utils.js - 默认导出
export default function formatDate(date) {
return new Intl.DateTimeFormat().format(date);
}
// app.js - 导入使用
import { PI, square, cube } from './math.js';
import formatDate from './utils.js';
import * as math from './math.js'; // 命名空间导入
console.log(PI); // 3.14159
console.log(square(5)); // 25
console.log(math.cube(3)); // 27
console.log(formatDate(new Date()));
模块加载时序图:
解构赋值:简洁的数据提取
解构赋值提供了一种从数组或对象中提取数据的简洁语法。
// 数组解构
const numbers = [1, 2, 3, 4, 5];
const [first, second, ...rest] = numbers;
console.log(first, second, rest); // 1, 2, [3, 4, 5]
// 对象解构
const user = {
id: 1,
name: 'John Doe',
email: 'john@example.com',
address: {
city: 'New York',
country: 'USA'
}
};
const { name, email, address: { city } } = user;
console.log(name, email, city); // John Doe, john@example.com, New York
// 函数参数解构
function printUser({ name, email, age = 25 }) {
console.log(`${name} (${email}), ${age} years old`);
}
printUser(user);
// 交换变量
let a = 1, b = 2;
[a, b] = [b, a];
console.log(a, b); // 2, 1
模板字符串:强大的字符串处理
模板字符串提供了多行字符串、字符串插值和标签模板等功能。
// 多行字符串
const multiLine = `
This is a
multi-line
string
`;
// 字符串插值
const name = 'John';
const age = 30;
const greeting = `Hello, my name is ${name} and I'm ${age} years old.`;
// 表达式计算
const price = 19.99;
const quantity = 3;
const total = `Total: $${(price * quantity).toFixed(2)}`;
// 标签模板
function highlight(strings, ...values) {
return strings.reduce((result, str, i) => {
const value = values[i] ? `<strong>${values[i]}</strong>` : '';
return result + str + value;
}, '');
}
const message = highlight`Hello ${name}, welcome to our ${'website'}!`;
console.log(message); // Hello <strong>John</strong>, welcome to our <strong>website</strong>!
扩展运算符与rest参数
扩展运算符和rest参数提供了处理函数参数和数组/对象的强大工具。
// 数组扩展
const arr1 = [1, 2, 3];
const arr2 = [4, 5, 6];
const combined = [...arr1, ...arr2]; // [1, 2, 3, 4, 5, 6]
// 对象扩展
const obj1 = { a: 1, b: 2 };
const obj2 = { c: 3, d: 4 };
const merged = { ...obj1, ...obj2 }; // { a: 1, b: 2, c: 3, d: 4 }
// 函数参数处理
function sum(...numbers) {
return numbers.reduce((total, num) => total + num, 0);
}
console.log(sum(1, 2, 3, 4, 5)); // 15
// 解构配合rest参数
const [first, second, ...others] = [1, 2, 3, 4, 5];
console.log(first, second, others); // 1, 2, [3, 4, 5]
// 浅拷贝应用
const original = { x: 1, y: 2 };
const copy = { ...original };
增强的对象字面量
ES6为对象字面量提供了更简洁的语法和新的功能。
// 属性简写
const name = 'John';
const age = 30;
const person = { name, age }; // { name: 'John', age: 30 }
// 方法简写
const calculator = {
add(a, b) {
return a + b;
},
multiply(a, b) {
return a * b;
}
};
// 计算属性名
const propName = 'status';
const dynamicObj = {
[propName]: 'active',
['user_' + Math.random()]: 'randomUser'
};
// Object.assign与扩展运算符对比
const defaults = { theme: 'light', notifications: true };
const userSettings = { theme: 'dark' };
// 使用Object.assign
const settings1 = Object.assign({}, defaults, userSettings);
// 使用扩展运算符
const settings2 = { ...defaults, ...userSettings };
Map、Set、WeakMap、WeakSet
ES6引入了新的数据结构,提供了比传统对象和数组更专业的解决方案。
// Map vs Object
const map = new Map();
map.set('name', 'John');
map.set(42, 'The Answer');
map.set({}, 'Object key');
console.log(map.get('name')); // John
console.log(map.size); // 3
// Set去重
const numbers = [1, 2, 2, 3, 4, 4, 5];
const uniqueNumbers = [...new Set(numbers)]; // [1, 2, 3, 4, 5]
// WeakMap用于私有数据
const privateData = new WeakMap();
class Person {
constructor(name) {
privateData.set(this, { name });
}
getName() {
return privateData.get(this).name;
}
}
// 不同数据结构的特性对比
数据结构选择指南:
| 需求场景 | 推荐数据结构 | 原因 |
|---|---|---|
| 键值对存储 | Map | 键可以是任意类型,有序迭代 |
| 唯一值集合 | Set | 自动去重,高效的存在性检查 |
| 对象私有数据 | WeakMap | 不影响垃圾回收,键必须是对象 |
| 简单配置对象 | Object | 字面量语法简洁,JSON兼容 |
| 频繁增删操作 | Map/Set | 性能优于数组的splice操作 |
Proxy与Reflect:元编程的强大工具
Proxy和Reflect提供了对对象基本操作的拦截和自定义能力。
// Proxy示例:数据验证
const validator = {
set(target, property, value) {
if (property === 'age') {
if (typeof value !== 'number' || value < 0) {
throw new TypeError('Age must be a positive number');
}
}
return Reflect.set(target, property, value);
}
};
const person = new Proxy({}, validator);
person.age = 25; // 成功
// person.age = -5; // TypeError: Age must be a positive number
// Proxy实现负索引数组
function createNegativeIndexArray(array) {
return new Proxy(array, {
get(target, index) {
const idx = parseInt(index);
if (idx < 0) {
return target[target.length + idx];
}
return target[idx];
}
});
}
const arr = createNegativeIndexArray([1, 2, 3, 4, 5]);
console.log(arr[-1]); // 5
console.log(arr[-2]); // 4
// Reflect的使用
const obj = { a: 1 };
console.log(Reflect.get(obj, 'a')); // 1
Reflect.set(obj, 'b', 2);
console.log(obj.b); // 2
## 异步编程与Promise实战
在现代JavaScript开发中,异步编程是不可或缺的核心技能。从早期的回调地狱到如今的Promise和async/await,JavaScript的异步处理方式经历了革命性的演进。掌握Promise不仅能让代码更加优雅,更是前端工程师面试中的必考知识点。
### Promise基础概念与三种状态
Promise是JavaScript中处理异步操作的标准化方案,它代表一个异步操作的最终完成(或失败)及其结果值。每个Promise对象都有三种可能的状态:
| 状态 | 描述 | 特性 |
|------|------|------|
| **pending** | 初始状态,既不是成功也不是失败 | 可转换为fulfilled或rejected |
| **fulfilled** | 操作成功完成 | 具有不可变的终值 |
| **rejected** | 操作失败 | 具有不可变的拒因 |
```javascript
// Promise基本用法示例
const promise = new Promise((resolve, reject) => {
// 异步操作
setTimeout(() => {
const success = Math.random() > 0.5;
if (success) {
resolve('操作成功!');
} else {
reject(new Error('操作失败!'));
}
}, 1000);
});
promise
.then(result => console.log(result))
.catch(error => console.error(error));
Promise链式调用的魔力
Promise的真正威力在于其链式调用能力,这彻底解决了回调地狱的问题:
function asyncOperation1() {
return new Promise(resolve => setTimeout(() => resolve(10), 1000));
}
function asyncOperation2(value) {
return new Promise(resolve => setTimeout(() => resolve(value * 2), 500));
}
function asyncOperation3(value) {
return new Promise(resolve => setTimeout(() => resolve(value + 5), 300));
}
// 链式调用示例
asyncOperation1()
.then(result1 => {
console.log('第一步结果:', result1);
return asyncOperation2(result1);
})
.then(result2 => {
console.log('第二步结果:', result2);
return asyncOperation3(result2);
})
.then(finalResult => {
console.log('最终结果:', finalResult);
})
.catch(error => console.error('错误:', error));
Promise常用静态方法详解
Promise.all - 并行处理多个异步操作
const promises = [
fetch('/api/user/1'),
fetch('/api/user/2'),
fetch('/api/user/3')
];
Promise.all(promises)
.then(responses => Promise.all(responses.map(r => r.json())))
.then(users => {
console.log('所有用户数据:', users);
})
.catch(error => {
console.error('有一个请求失败:', error);
});
Promise.race - 竞速模式
const timeoutPromise = new Promise((_, reject) =>
setTimeout(() => reject(new Error('请求超时')), 5000)
);
const apiPromise = fetch('/api/data');
Promise.race([apiPromise, timeoutPromise])
.then(response => response.json())
.then(data => console.log('数据:', data))
.catch(error => console.error('错误:', error));
Promise.allSettled - 等待所有Promise完成
const promises = [
Promise.resolve('成功1'),
Promise.reject(new Error('失败1')),
Promise.resolve('成功2')
];
Promise.allSettled(promises)
.then(results => {
results.forEach((result, index) => {
if (result.status === 'fulfilled') {
console.log(`Promise ${index}:`, result.value);
}
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考



