JavaScript 知识总结与面试题
JavaScript 核心知识体系化整理:数据类型、作用域与闭包、原型链、异步编程(Promise / async-await)、ES6+ 新特性与数组方法,配代码示例与面试题,适合查阅与面试准备。
一、JavaScript 基础概念
1. 什么是 JavaScript?
- 一种轻量级的脚本语言
- 用于 Web 开发,实现页面交互
- 支持面向对象、函数式编程
- 单线程、异步执行
2. JavaScript 组成部分
- ECMAScript:核心语法标准
- DOM:文档对象模型,操作 HTML 元素
- BOM:浏览器对象模型,操作浏览器窗口
3. JavaScript 运行机制
- 单线程执行
- 事件循环(Event Loop)
- 执行栈、任务队列(宏任务、微任务)
二、数据类型
1. 基本数据类型
| 类型 | 说明 | 示例 |
|---|---|---|
String |
字符串 | "hello" |
Number |
数字 | 42 |
Boolean |
布尔值 | true |
Null |
空值 | null |
Undefined |
未定义 | undefined |
Symbol |
唯一标识符 | Symbol('id') |
BigInt |
大整数 | 123n |
2. 引用数据类型
Object:对象Array:数组Function:函数Date:日期RegExp:正则表达式
3. 类型判断
// typeoftypeof 'hello' // 'string'typeof 42 // 'number'typeof null // 'object'(历史遗留问题)// instanceof[] instanceof Array // true{} instanceof Object // true// Object.prototype.toStringObject.prototype.toString.call([]) // '[object Array]'Object.prototype.toString.call(null) // '[object Null]'4. 类型转换
// 显式转换Number('42') // 42String(42) // '42'Boolean(0) // false// 隐式转换'5' + 3 // '53'(字符串拼接)'5' - 3 // 2(数字运算)!!'hello' // true(布尔转换)三、变量与作用域
1. 变量声明
| 关键字 | 作用域 | 变量提升 | 重复声明 |
|---|---|---|---|
var |
函数作用域 | 是 | 允许 |
let |
块级作用域 | 是(暂时性死区) | 不允许 |
const |
块级作用域 | 是(暂时性死区) | 不允许,且必须初始化 |
2. 作用域链
function outer() { var x = 1; function inner() { var y = 2; console.log(x + y); // 3,x 来自外层作用域 } inner();}3. 闭包
function createCounter() { let count = 0; return { increment() { count++; return count; }, getCount() { return count; } };}const counter = createCounter();counter.increment(); // 1counter.increment(); // 2counter.getCount(); // 2四、函数
1. 函数定义
// 函数声明function add(a, b) { return a + b;}// 函数表达式const multiply = function(a, b) { return a * b;};// 箭头函数const divide = (a, b) => a / b;2. 箭头函数特点
// 没有自己的 thisconst obj = { name: 'test', sayHello: () => { console.log(this.name); // undefined }};// 不能作为构造函数const Person = () => {};new Person(); // TypeError// 没有 arguments 对象const fn = () => console.log(arguments); // ReferenceError3. this 指向
// 全局上下文console.log(this); // window(浏览器)/ global(Node.js)// 对象方法const obj = { name: 'test', greet() { console.log(this.name); // 'test' }};// 构造函数function Person(name) { this.name = name;}const p = new Person('Alice');console.log(p.name); // 'Alice'// 显式绑定obj.greet.call({ name: 'Bob' }); // 'Bob'4. 原型与原型链
function Person(name) { this.name = name;}Person.prototype.sayHello = function() { console.log(`Hello, ${this.name}`);};const p = new Person('Alice');p.sayHello(); // 'Hello, Alice'// 原型链p.__proto__ === Person.prototype // truePerson.prototype.__proto__ === Object.prototype // trueObject.prototype.__proto__ === null // true五、异步编程
1. 回调函数
function fetchData(callback) { setTimeout(() => { callback(null, { data: 'hello' }); }, 1000);}fetchData((error, result) => { if (error) { console.error(error); } else { console.log(result); }});2. Promise
const promise = new Promise((resolve, reject) => { setTimeout(() => { resolve('success'); // reject(new Error('failed')); }, 1000);});promise .then(result => console.log(result)) .catch(error => console.error(error));3. async/await
async function fetchData() { try { const result = await fetch('https://api.example.com/data'); const data = await result.json(); return data; } catch (error) { console.error(error); }}fetchData();4. 事件循环
console.log('1'); // 同步setTimeout(() => { console.log('2'); // 宏任务}, 0);Promise.resolve().then(() => { console.log('3'); // 微任务});console.log('4'); // 同步// 输出顺序:1, 4, 3, 2六、ES6+ 新特性
1. 解构赋值
// 对象解构const { name, age } = { name: 'Alice', age: 25 };// 数组解构const [a, b, ...rest] = [1, 2, 3, 4, 5];// 默认值const { name = 'Unknown' } = {};2. 扩展运算符
// 数组扩展const arr1 = [1, 2, 3];const arr2 = [...arr1, 4, 5]; // [1, 2, 3, 4, 5]// 对象扩展const obj1 = { a: 1 };const obj2 = { ...obj1, b: 2 }; // { a: 1, b: 2 }3. 模板字符串
const name = 'Alice';const greeting = `Hello, ${name}!`;4. 类
class Person { constructor(name) { this.name = name; } sayHello() { console.log(`Hello, ${this.name}`); }}class Student extends Person { constructor(name, grade) { super(name); this.grade = grade; }}5. 模块化
// 导出export const name = 'Alice';export function greet() { console.log('Hello');}// 导入import { name, greet } from './module.js';七、数组方法
1. 迭代方法
const arr = [1, 2, 3, 4, 5];// map:映射arr.map(x => x * 2); // [2, 4, 6, 8, 10]// filter:过滤arr.filter(x => x > 2); // [3, 4, 5]// reduce:归约arr.reduce((acc, x) => acc + x, 0); // 15// find:查找第一个匹配项arr.find(x => x > 2); // 3// findIndex:查找索引arr.findIndex(x => x > 2); // 22. 其他方法
// 拼接arr.concat([6, 7]); // [1, 2, 3, 4, 5, 6, 7]// 切片arr.slice(1, 3); // [2, 3]// 排序arr.sort((a, b) => a - b); // 升序// 反转arr.reverse(); // [5, 4, 3, 2, 1]八、错误处理
1. try-catch-finally
try { // 可能出错的代码 throw new Error('Something went wrong');} catch (error) { // 处理错误 console.error(error.message);} finally { // 无论是否出错都会执行 console.log('Done');}2. 错误类型
| 错误类型 | 说明 |
|---|---|
Error |
通用错误 |
SyntaxError |
语法错误 |
TypeError |
类型错误 |
ReferenceError |
引用错误 |
RangeError |
范围错误 |
九、DOM 操作
1. 选择元素
// 通过 IDdocument.getElementById('myId');// 通过类名document.getElementsByClassName('myClass');// 通过标签名document.getElementsByTagName('div');// 通过选择器document.querySelector('.myClass');document.querySelectorAll('.myClass');2. 修改元素
// 修改内容element.textContent = 'Hello';element.innerHTML = '<strong>Hello</strong>';// 修改样式element.style.color = 'red';element.classList.add('active');element.classList.remove('active');// 修改属性element.setAttribute('src', 'image.jpg');element.getAttribute('src');3. 事件处理
// 添加事件监听element.addEventListener('click', handleClick);// 移除事件监听element.removeEventListener('click', handleClick);// 事件委托document.addEventListener('click', (e) => { if (e.target.matches('.btn')) { // 处理点击 }});十、常见面试题
基础概念
Q1:JavaScript 有哪些数据类型?
- 基本类型:String、Number、Boolean、Null、Undefined、Symbol、BigInt
- 引用类型:Object、Array、Function、Date、RegExp
Q2:null 和 undefined 的区别?
null:表示空值,主动设置undefined:表示未定义,变量声明但未赋值
Q3:== 和 === 的区别?
==:会进行类型转换后比较===:严格相等,不进行类型转换
作用域和闭包
Q4:什么是闭包?闭包的用途?
- 闭包是函数能够访问其词法作用域中的变量
- 用途:数据私有化、函数工厂、回调函数
Q5:var、let、const 的区别?
var:函数作用域,存在变量提升,可重复声明let:块级作用域,存在暂时性死区,不可重复声明const:块级作用域,必须初始化,不可重复声明
this 指向
Q6:this 的指向规则?
- 默认绑定:全局上下文指向 window
- 隐式绑定:对象方法指向该对象
- 显式绑定:call/apply/bind 指定 this
- new 绑定:构造函数中 this 指向新创建的对象
Q7:箭头函数的 this 指向?
- 箭头函数没有自己的 this
- 继承外层作用域的 this
异步编程
Q8:Promise 的三种状态?
- pending(等待中)
- fulfilled(已成功)
- rejected(已失败)
Q9:事件循环的执行顺序?
- 执行同步代码
- 执行微任务队列
- 执行宏任务队列
- 重复上述步骤
Q10:async/await 的工作原理?
- async 函数返回 Promise
- await 暂停执行,等待 Promise 完成
- 底层使用 generator 和 Promise 实现
ES6+ 特性
Q11:解构赋值的用途?
- 从对象或数组中提取值
- 简化变量声明
- 支持默认值
Q12:class 和 ES5 构造函数的区别?
- class 是语法糖,本质还是原型继承
- class 更清晰、更易读
- class 支持 extends 关键字
数组方法
Q13:map、filter、reduce 的区别?
map:映射,返回新数组,每个元素经过处理filter:过滤,返回符合条件的元素reduce:归约,将数组归约为单个值
Q14:forEach 和 map 的区别?
forEach:遍历数组,无返回值map:遍历数组,返回新数组
进阶问题
Q15:什么是原型链?
- 对象通过
__proto__属性链接到原型 - 访问属性时,会沿原型链查找
- 最终指向
Object.prototype.__proto__(null)
Q16:深拷贝和浅拷贝的区别?
- 浅拷贝:只复制第一层属性
- 深拷贝:递归复制所有层级
// 深拷贝实现function deepClone(obj) { if (obj === null || typeof obj !== 'object') return obj; if (obj instanceof Date) return new Date(obj); if (obj instanceof Array) return obj.map(item => deepClone(item)); const clone = {}; for (let key in obj) { if (obj.hasOwnProperty(key)) { clone[key] = deepClone(obj[key]); } } return clone;}Q17:什么是防抖和节流?
// 防抖:在事件触发后延迟执行,若期间再次触发则重新计时function debounce(fn, delay) { let timer = null; return function(...args) { clearTimeout(timer); timer = setTimeout(() => fn.apply(this, args), delay); };}// 节流:在一定时间内只执行一次function throttle(fn, interval) { let lastTime = 0; return function(...args) { const now = Date.now(); if (now - lastTime >= interval) { fn.apply(this, args); lastTime = now; } };}Q18:Promise.all 和 Promise.race 的区别?
Promise.all:等待所有 Promise 完成,任意一个失败则整体失败Promise.race:返回最先完成的 Promise,无论成功或失败
Q19:什么是事件委托?
- 将事件监听绑定到父元素
- 通过事件冒泡机制处理子元素事件
- 优点:减少事件监听数量,支持动态添加元素
Q20:如何实现继承?
// ES5 原型继承function Parent(name) { this.name = name;}Parent.prototype.sayHello = function() { console.log(this.name);};function Child(name, age) { Parent.call(this, name); this.age = age;}Child.prototype = Object.create(Parent.prototype);Child.prototype.constructor = Child;十一、最佳实践
- 使用严格模式:
'use strict'; - 避免全局变量:使用模块化或 IIFE
- 使用 let/const 代替 var:避免作用域问题
- 使用箭头函数简化代码:特别是回调函数
- 使用 Promise 或 async/await:避免回调地狱
- 优化性能:减少 DOM 操作、使用事件委托
十二、总结
JavaScript 是 Web 开发的核心语言,掌握其核心概念、异步编程、ES6+ 特性和最佳实践是成为优秀前端开发者的关键。