全栈手账 订阅 RSS

JavaScript 知识总结与面试题

JavaScript 核心知识体系化整理:数据类型、作用域与闭包、原型链、异步编程(Promise / async-await)、ES6+ 新特性与数组方法,配代码示例与面试题,适合查阅与面试准备。

读了 20 分钟 更新于 8 月 5 日

一、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. 类型判断

javascript
// 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. 类型转换

javascript
// 显式转换Number('42')      // 42String(42)        // '42'Boolean(0)        // false// 隐式转换'5' + 3           // '53'(字符串拼接)'5' - 3           // 2(数字运算)!!'hello'         // true(布尔转换)

三、变量与作用域

1. 变量声明

关键字 作用域 变量提升 重复声明
var 函数作用域 是 允许
let 块级作用域 是(暂时性死区) 不允许
const 块级作用域 是(暂时性死区) 不允许,且必须初始化

2. 作用域链

javascript
function outer() {    var x = 1;        function inner() {        var y = 2;        console.log(x + y); // 3,x 来自外层作用域    }        inner();}

3. 闭包

javascript
function createCounter() {    let count = 0;        return {        increment() {            count++;            return count;        },        getCount() {            return count;        }    };}const counter = createCounter();counter.increment(); // 1counter.increment(); // 2counter.getCount();  // 2

四、函数

1. 函数定义

javascript
// 函数声明function add(a, b) {    return a + b;}// 函数表达式const multiply = function(a, b) {    return a * b;};// 箭头函数const divide = (a, b) => a / b;

2. 箭头函数特点

javascript
// 没有自己的 thisconst obj = {    name: 'test',    sayHello: () => {        console.log(this.name); // undefined    }};// 不能作为构造函数const Person = () => {};new Person(); // TypeError// 没有 arguments 对象const fn = () => console.log(arguments); // ReferenceError

3. this 指向

javascript
// 全局上下文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. 原型与原型链

javascript
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. 回调函数

javascript
function fetchData(callback) {    setTimeout(() => {        callback(null, { data: 'hello' });    }, 1000);}fetchData((error, result) => {    if (error) {        console.error(error);    } else {        console.log(result);    }});

2. Promise

javascript
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

javascript
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. 事件循环

javascript
console.log('1'); // 同步setTimeout(() => {    console.log('2'); // 宏任务}, 0);Promise.resolve().then(() => {    console.log('3'); // 微任务});console.log('4'); // 同步// 输出顺序:1, 4, 3, 2

六、ES6+ 新特性

1. 解构赋值

javascript
// 对象解构const { name, age } = { name: 'Alice', age: 25 };// 数组解构const [a, b, ...rest] = [1, 2, 3, 4, 5];// 默认值const { name = 'Unknown' } = {};

2. 扩展运算符

javascript
// 数组扩展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. 模板字符串

javascript
const name = 'Alice';const greeting = `Hello, ${name}!`;

4. 类

javascript
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. 模块化

javascript
// 导出export const name = 'Alice';export function greet() {    console.log('Hello');}// 导入import { name, greet } from './module.js';

七、数组方法

1. 迭代方法

javascript
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); // 2

2. 其他方法

javascript
// 拼接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

javascript
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. 选择元素

javascript
// 通过 IDdocument.getElementById('myId');// 通过类名document.getElementsByClassName('myClass');// 通过标签名document.getElementsByTagName('div');// 通过选择器document.querySelector('.myClass');document.querySelectorAll('.myClass');

2. 修改元素

javascript
// 修改内容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. 事件处理

javascript
// 添加事件监听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 的指向规则?

  1. 默认绑定:全局上下文指向 window
  2. 隐式绑定:对象方法指向该对象
  3. 显式绑定:call/apply/bind 指定 this
  4. new 绑定:构造函数中 this 指向新创建的对象

Q7:箭头函数的 this 指向?

  • 箭头函数没有自己的 this
  • 继承外层作用域的 this

异步编程

Q8:Promise 的三种状态?

  • pending(等待中)
  • fulfilled(已成功)
  • rejected(已失败)

Q9:事件循环的执行顺序?

  1. 执行同步代码
  2. 执行微任务队列
  3. 执行宏任务队列
  4. 重复上述步骤

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:深拷贝和浅拷贝的区别?

  • 浅拷贝:只复制第一层属性
  • 深拷贝:递归复制所有层级
javascript
// 深拷贝实现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:什么是防抖和节流?

javascript
// 防抖:在事件触发后延迟执行,若期间再次触发则重新计时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:如何实现继承?

javascript
// 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;

十一、最佳实践

  1. 使用严格模式:'use strict';
  2. 避免全局变量:使用模块化或 IIFE
  3. 使用 let/const 代替 var:避免作用域问题
  4. 使用箭头函数简化代码:特别是回调函数
  5. 使用 Promise 或 async/await:避免回调地狱
  6. 优化性能:减少 DOM 操作、使用事件委托

十二、总结

JavaScript 是 Web 开发的核心语言,掌握其核心概念、异步编程、ES6+ 特性和最佳实践是成为优秀前端开发者的关键。

前端、后端、部署、客服都是我一个人。写这里的东西都是真踩过的坑,不是抄来的教程。