本文汇总了前端开发中99% 会遇到的 JS 核心知识点、高频踩坑、大厂面试题每一个知识点都搭配代码示例踩坑点附落地解决方案面试题附详细解析适合前端新手查漏补缺、老手复习巩固可直接用于开发实战和面试准备一、JavaScript 核心基础知识点必掌握1.1 数据类型原始类型 引用类型JS 数据类型分为原始值类型和引用数据类型是前端开发的基石。原始类型7 种Undefined、Null、Boolean、Number、String、Symbol、BigIntES11新增引用类型Object包含Array、Function、Date、RegExp等核心区别原始类型存栈内存值不可变引用类型存堆内存栈中存储堆地址原始类型赋值是值拷贝引用类型赋值是地址拷贝原始类型比较是值比较引用类型比较是地址比较代码示例// 原始类型值拷贝互不影响 let a 10; let b a; b 20; console.log(a); // 10 // 引用类型地址拷贝修改会相互影响 let obj1 { name: 掘金 }; let obj2 obj1; obj2.name 前端开发; console.log(obj1.name); // 前端开发 // 精准类型判断 Object.prototype.toString.call(null); // [object Null] Object.prototype.toString.call([]); // [object Array]为什么要加 BigIntNumber 局限只能精确表示±2⁵³−1范围内的整数约 9e15。精度丢失问题9007199254740992 9007199254740993; // true错误 // 1. 字面量加 n const a 123n; const b -456n; // 2. 构造函数 const c BigInt(789); const d BigInt(9007199254740992); // 3. 类型判断 typeof a; // bigint //与 Number 不兼容 不支持小数、Math 方法、JSON.stringify 123n 123; // TypeError不能混合运算 123n 123; // falseBigInt 解决支持任意精度整数适合金融、区块链、大 ID、密码学。1.2 变量声明var /let/const前端最基础的声明规则也是面试必考、开发必用知识点。特性varletconst变量提升✅ 存在❌ 暂时性死区❌ 暂时性死区块级作用域❌ 无✅ 有✅ 有重复声明✅ 允许❌ 不允许❌ 不允许重新赋值✅ 允许✅ 允许❌ 不允许代码示例// var变量提升 全局污染 console.log(num); // undefined if (true) var num 10; console.log(num); // 10 // let块级作用域隔离 let age 20; if (true) { let age 30; } console.log(age); // 20 // const必须初始化引用类型可改属性 const PI 3.14; const user { name: 张三 }; user.name 李四; // 合法1.3 类型转换显式 隐式JS 是弱类型语言类型转换是开发高频操作。显式转换Number()、String()、Boolean()、parseInt()隐式转换、-、、if判断等自动触发代码示例// 显式转换 Number(123); // 123 String(true); // true Boolean(0); // false // 隐式转换 1 2; // 12数字转字符串 12 - 0; // 12字符串转数字 if (1) {} // 1转true1.4 运算符核心 / / 短路运算 / 空值合并// 隐式转换后比较严格比较类型值 0 ; // true 0 ; // false // 短路运算一假则假、||一真则真 const name null || 默认名称; const age 18 成年; // 空值合并??仅null/undefined时取默认值开发推荐 const obj { age: 0 }; obj.age ?? 18; // 0 obj.height ?? 180; // 1801.5 函数核心普通函数 / 箭头函数 /this箭头函数 vs 普通函数箭头函数没有this继承父级作用域的this没有arguments、不能用作构造函数、没有原型简写语法适合回调函数代码示例// 普通函数this指向调用者 function fn() { console.log(this); } fn(); // window/global // 箭头函数this继承外层 const obj { fn: () console.log(this) }; obj.fn(); // window1.6 数组高频方法开发必备const arr [1,2,3]; // 遍历forEach、map、filter、find、some、every arr.map(item item * 2); // [2,4,6] arr.filter(item item 1); // [2,3] // 增删改查push/pop/unshift/shift/splice arr.push(4); // [1,2,3,4] arr.splice(1,1); // 删除索引1的元素 → [1,3,4] // 高阶reduce求和、去重、扁平化 arr.reduce((sum, cur) sum cur, 0); // 81.7 闭包核心概念定义函数嵌套函数内部函数访问外部函数变量形成闭包。作用私有化变量、延长变量生命周期、实现柯里化风险滥用会导致内存泄漏代码示例function outer() { let num 10; return function inner() { console.log(num); // 访问外部变量 → 闭包 }; } const fn outer(); fn(); // 101.8 原型与原型链JS 继承的核心机制面试必考。所有对象都有__proto__指向构造函数的prototype原型链对象查找属性 / 方法的路径终点是null代码示例function Person(name) { this.name name; } // 原型方法 Person.prototype.sayHi function() { console.log(this.name); }; const p new Person(张三); p.sayHi(); // 张三 // 原型链关系 p.__proto__ Person.prototype; Person.prototype.__proto__ Object.prototype; Object.prototype.__proto__ null;1.9异步编程回调 / Promise /async-awaitJS 是单线程语言异步解决阻塞问题。// Promise 基础 const p new Promise((resolve, reject) { setTimeout(() resolve(成功), 1000); }); p.then(res console.log(res)); // async-await语法糖开发首选 async function getData() { const res await p; console.log(res); } getData();1.10事件循环宏任务 / 微任务JS 执行机制大厂面试必考题执行栈 → 微任务队列 → 宏任务队列微任务Promise.then/catch/finally、MutationObserver宏任务setTimeout、setInterval、ajax、DOM事件代码示例console.log(1); setTimeout(() console.log(2), 0); // 宏任务 Promise.resolve().then(() console.log(3)); // 微任务 console.log(4); // 执行顺序1 → 4 → 3 → 2二、JavaScript 开发高频踩坑汇总99% 开发者都遇到过2.1 隐式类型转换踩坑 滥用错误场景自动隐式转换导致逻辑错误console.log(0 ); // true console.log( false); // true原因会先转换类型再比较解决方案开发永远优先用 仅判断null/undefined用let a; if (a null) { // 等价于 a null || a undefined console.log(变量为空); }2.2 forEach 中使用 await 失效错误场景forEach 不支持异步无法按顺序执行const arr [1,2,3]; arr.forEach(async item { await new Promise(r setTimeout(r,1000)); console.log(item); // 1秒后同时输出1、2、3 });解决方案用for...of/ 普通 for 循环(async () { for(let item of arr) { await new Promise(r setTimeout(r,1000)); console.log(item); // 每隔1秒输出 } })();2.3 引用类型浅拷贝导致数据篡改错误场景对象 / 数组直接赋值修改新变量污染原数据let obj1 { name: 张三 }; let obj2 obj1; obj2.name 李四; console.log(obj1.name); // 李四解决方案浅拷贝.../Object.assign深拷贝JSON.parse/ 手写深拷贝// 浅拷贝 let obj2 {...obj1}; // 深拷贝无函数/undefined时 let deepObj JSON.parse(JSON.stringify(obj1));2.4 this 指向丢失错误场景定时器 / 回调函数中 this 指向改变const obj { name: 张三, sayName() { setTimeout(function() { console.log(this.name); // undefined }, 100); } };解决方案箭头函数 / 存 this/bind// 箭头函数 setTimeout(() console.log(this.name), 100);2.5 数组空位导致方法异常错误场景数组空位empty被 forEach/map 跳过const arr [1,,3]; arr.forEach(item console.log(item)); // 只输出1、3解决方案初始化数组时避免空位用fill填充const arr [1, undefined, 3];2.6 闭包导致内存泄漏错误场景闭包变量长期占用内存不释放function leak() { let bigData new Array(1000000).fill(数据); return () bigData; } const fn leak(); // bigData永远不被回收解决方案使用完手动置空fn null; // 释放内存2.7 异步同步混淆执行顺序错误错误场景直接获取异步函数返回值function getData() { setTimeout(() return 数据, 1000); } const res getData(); console.log(res); // undefined解决方案用 Promise/async-await 接收2.8 函数默认参数踩坑错误场景默认参数仅在undefined时生效function fn(a 10) { console.log(a); } fn(null); // null fn(undefined); // 10三、大厂高频 JavaScript 面试题附答案 解析3.1 数据类型相关必考题目 1JS 有哪些数据类型Symbol 和 BigInt 的特点答案JS 共8 种原始类型 引用类型Object其中原始类型包含7 种原始类型Undefined、Null、Boolean、Number、String、SymbolES2015、BigIntES20201 种引用类型Object包含Array、Function、Date、RegExp等子类型Symbol 特点独一无二不可重复Symbol(a) ! Symbol(a)可作为对象属性名避免属性冲突不能参与隐式类型转换Symbol转字符串需手动调用toString()BigInt 特点解决Number精度丢失问题Number仅能精确表示±2^53-1范围内整数定义方式123n/BigInt(456)不可与Number混合运算1n 2会抛错题目 2typeof 和 instanceof 的区别手写 instanceof 原理答案对比项typeofinstanceof作用判断原始类型除 null和引用类型判断引用类型的继承关系返回值字符串如number、object布尔值true/false特殊点typeof null object历史 bug无法判断原始类型如1 instanceof Number false手写 instanceof 原理/** * 手写instanceof * param {*} left 待检测对象 * param {*} right 构造函数 * returns {boolean} */ function myInstanceof(left, right) { // 原始类型直接返回false if (typeof left ! object || left null) return false; // 获取右构造函数的原型对象 let prototype right.prototype; // 获取左对象的隐式原型 left left.__proto__; // 遍历原型链 while (true) { // 原型链终点为null if (left null) return false; // 原型匹配 if (left prototype) return true; // 向上遍历原型链 left left.__proto__; } } // 测试 console.log(myInstanceof([], Array)); // true console.log(myInstanceof({}, Object)); // true console.log(myInstanceof(123, Number)); // false3.2 变量声明var/let/const题目var、let、const 的区别暂时性死区是什么答案核心差异体现在变量提升、块级作用域、重复声明、重新赋值四个维度var存在变量提升无块级作用域可重复声明可重新赋值let无变量提升存在暂时性死区有块级作用域不可重复声明可重新赋值const无变量提升有块级作用域不可重复声明不可重新赋值引用类型属性可改暂时性死区TDZ在代码块内使用let/const声明变量前变量处于 “不可访问” 状态称为暂时性死区。console.log(a); // 报错Cannot access a before initialization let a 10;3.3 作用域与作用域链题目 1JS 的作用域有哪些作用域链的作用答案JS 采用词法作用域静态作用域作用域分为 3 类全局作用域代码最外层全局可访问函数作用域函数内部定义仅函数内可访问块级作用域{}包裹let/const生效如if/for/switch作用域链当访问变量时会从当前作用域向上查找直到全局作用域这条查找链条就是作用域链。作用域链决定了变量的访问权限和优先级。题目 2手写实现块级作用域用 var 模拟 let答案利用 ** 立即执行函数IIFE** 的函数作用域模拟块级作用域// 原代码 for (let i 0; i 3; i) { setTimeout(() console.log(i), 100); } // 输出 0 1 2 // 用var模拟 for (var i 0; i 3; i) { (function(j) { setTimeout(() console.log(j), 100); })(i); } // 输出 0 1 23.4 闭包核心难点题目 1什么是闭包闭包的应用场景优缺点答案闭包定义内部函数访问外部函数的变量 / 参数且内部函数被外部引用形成闭包。应用场景私有化变量隐藏内部属性仅暴露接口如 JS 模块、单例模式防抖 / 节流缓存定时器标识柯里化函数参数复用、延迟执行模块模式实现单例、封装私有属性优缺点优点私有化变量、延长变量生命周期、实现函数柯里化缺点闭包会占用内存若未及时释放易导致内存泄漏大量闭包 大对象题目 2手写闭包实现私有属性答案/** * 闭包实现私有属性 */ function Person(name) { // 私有属性 let _age 0; // 公有方法闭包访问私有属性 this.getName function() { return name; }; this.getAge function() { return _age; }; this.setAge function(val) { if (val 0) _age val; }; } // 测试 const p new Person(张三); console.log(p.getName()); // 张三 console.log(p.getAge()); // 0 p.setAge(20); console.log(p.getAge()); // 20 console.log(p._age); // undefined私有属性无法直接访问题目 3闭包导致的内存泄漏如何解决答案及时解除引用闭包函数不再使用时将其赋值为null释放对内部变量的引用避免滥用闭包减少闭包嵌套层级避免缓存大对象使用弱引用ES6 的WeakMap/WeakSet存储闭包数据垃圾回收时自动释放无引用限制3.5 原型基础题目 1原型、原型对象、构造函数的关系答案构造函数通过new创建实例的函数如function Person() {}原型对象每个函数都有prototype属性指向原型对象每个实例都有__proto__属性指向构造函数的原型对象关系实例.__proto__ 构造函数.prototype原型对象的constructor属性指向构造函数题目 2JS 的继承方式有哪些手写 ES6 类继承答案JS 常见继承方式原型链继承、构造函数继承、组合继承、原型式继承、寄生式继承、寄生组合式继承最优、ES6 class 继承。手写 ES6 class 继承/** * ES6 class继承 */ class Parent { constructor(name) { this.name name; } // 原型方法 sayHi() { console.log(Hello, ${this.name}); } // 静态方法 static create() { return new Parent(Static); } } class Child extends Parent { constructor(name, age) { // 必须调用super初始化父类构造函数 super(name); this.age age; } // 重写原型方法 sayHi() { // 调用父类方法 super.sayHi(); console.log(Im ${this.age} years old); } } // 测试 const c new Child(李四, 18); c.sayHi(); // Hello, 李四 → Im 18 years old console.log(Child.create()); // Parent { name: Static }3.6 原型链深入题目手写实现寄生组合式继承最优继承方式答案寄生组合式继承解决了组合继承调用两次父类构造函数的效率问题是 ES6 之前的最优方案/** * 寄生组合式继承 * param {Function} Child 子类 * param {Function} Parent 父类 */ function inheritPrototype(Child, Parent) { // 创建父类原型的浅拷贝避免修改父类原型 const prototype Object.create(Parent.prototype); // 修正constructor指向 prototype.constructor Child; // 子类原型指向拷贝的父类原型 Child.prototype prototype; } // 父类 function Parent(name) { this.name name; } Parent.prototype.sayHi function() { console.log(Hi, ${this.name}); }; // 子类 function Child(name, age) { // 调用父类构造函数初始化属性 Parent.call(this, name); this.age age; } // 实现继承 inheritPrototype(Child, Parent); // 子类添加方法 Child.prototype.sayAge function() { console.log(Age: ${this.age}); }; // 测试 const c new Child(王五, 20); c.sayHi(); // Hi, 王五 c.sayAge(); // Age: 20 console.log(c instanceof Child); // true console.log(c instanceof Parent); // true3.7 Promise核心题目 1Promise 的三种状态状态能否逆转then 方法的执行机制答案三种状态pending初始状态未完成fulfilledresolved成功状态rejected失败状态状态逆转状态一旦改变不可逆转pending→fulfilled或pending→rejected不可逆then 执行机制then是微任务异步执行返回新的 Promise支持链式调用若then回调返回非 Promise 值会包装为resolved状态的 Promise若返回 Promise会等待其状态改变题目 2手写实现 Promise简易版含 resolve/reject/then答案/** * 简易版Promise实现 */ class MyPromise { // 状态 #state pending; #value undefined; #reason undefined; // 回调队列处理异步resolve/reject #onFulfilledCallbacks []; #onRejectedCallbacks []; constructor(executor) { // 绑定this避免执行时this丢失 const resolve (value) { if (this.#state pending) { this.#state fulfilled; this.#value value; // 执行成功回调 this.#onFulfilledCallbacks.forEach(cb cb()); } }; const reject (reason) { if (this.#state pending) { this.#state rejected; this.#reason reason; // 执行失败回调 this.#onRejectedCallbacks.forEach(cb cb()); } }; try { // 执行执行器 executor(resolve, reject); } catch (err) { // 执行器抛错触发reject reject(err); } } // then方法 then(onFulfilled, onRejected) { // 处理参数默认值值穿透 onFulfilled typeof onFulfilled function ? onFulfilled : (v) v; onRejected typeof onRejected function ? onRejected : (r) { throw r }; // 返回新的Promise实现链式调用 return new MyPromise((resolve, reject) { // 执行成功回调 const handleFulfilled () { try { const result onFulfilled(this.#value); // 处理返回Promise的情况 if (result instanceof MyPromise) { result.then(resolve, reject); } else { resolve(result); } } catch (err) { reject(err); } }; // 执行失败回调 const handleRejected () { try { const result onRejected(this.#reason); if (result instanceof MyPromise) { result.then(resolve, reject); } else { resolve(result); } } catch (err) { reject(err); } }; // 同步状态时直接执行 if (this.#state fulfilled) { handleFulfilled(); } else if (this.#state rejected) { handleRejected(); } else { // 异步状态时存入回调队列 this.#onFulfilledCallbacks.push(handleFulfilled); this.#onRejectedCallbacks.push(handleRejected); } }); } // catch方法等价于then(null, onRejected) catch(onRejected) { return this.then(null, onRejected); } // 静态方法resolve static resolve(value) { return new MyPromise(resolve resolve(value)); } // 静态方法reject static reject(reason) { return new MyPromise((resolve, reject) reject(reason)); } } // 测试 new MyPromise((resolve) { setTimeout(() resolve(Promise测试), 1000); }).then(res { console.log(res); // 1秒后输出 Promise测试 return 123; }).then(res { console.log(res); // 输出 123 });3.8 事件循环Event Loop题目 1JS 的事件循环机制宏任务与微任务的区别执行顺序答案JS 是单线程语言事件循环是解决异步操作的核心机制流程如下执行栈先执行同步代码微任务队列同步代码执行完清空所有微任务宏任务队列微任务清空后取一个宏任务执行循环往复微任务→宏任务→微任务→宏任务宏任务script整体代码、setTimeout、setInterval、AJAX请求、DOM事件、UI渲染微任务Promise.then/catch/finally、MutationObserver、queueMicrotask、process.nextTickNode.js题目 2分析以下代码的执行顺序大厂经典题console.log(1); setTimeout(() { console.log(2); Promise.resolve().then(() { console.log(3); }); }, 0); Promise.resolve().then(() { console.log(4); setTimeout(() { console.log(5); }, 0); }); console.log(6);答案执行顺序1 → 6 → 4 → 2 → 3 → 5四、总结本文覆盖了JS 核心基础、开发 99% 高频踩坑、大厂必考面试题所有知识点都搭配了可直接运行的代码示例踩坑点提供了落地解决方案手写题是面试高频考点。