JS学习与简单复盘

📅 2026/7/6 3:07:24
JS学习与简单复盘
学习资料学习JavaScript这一篇就够了-CSDN博客一、JS 基础语法1. JS的数据类型有哪些怎么分类通俗标准答案一共7种分为两大类基本数据类型简单类型/值类型string、number、boolean、undefined、null、symbol引用数据类型复杂类型object数组Array、函数Function、普通对象都属于Object核心区别基本类型存在栈内存赋值是拷贝本身的值互不影响引用类型变量存内存地址真实数据存在堆内存赋值只拷贝地址两个变量会互相影响2. null 和 undefined 的区别通俗直白答案undefined系统自动赋值定义了变量但是没给值、函数无返回值、对象不存在的属性默认都是undefinednull开发者手动赋值代表空对象、手动清空变量面试一句话总结undefined是不知道是什么null是空对象typeof null 结果是objectJS历史bug3. 和 的区别必考标准答案 弱相等只比较值会自动隐式类型转换转换成相同类型再对比 强相等严格相等先对比数据类型类型不一样直接false类型相同再对比值不做类型转换经典面试特例null undefined 结果为truenull undefined 为false4. JS 隐式类型转换规则大白话总结运算、 判断的时候JS自动帮你转类型字符串数字数字转字符串做拼接减乘除、大小比较字符串转数字布尔判断0、、null、undefined、NaN 为 false其余全是true5. typeof 能判断哪些类型缺点是什么typeof 判断结果string/number/boolean/undefined/symbol/function/object二、数组高频八股6. splice、slice、split 三个方法区别小白最简单背诵版splice()修改原数组删除/新增/替换数组元素参数(起始下标,删除个数,新增元素)slice()不修改原数组截取数组/字符串参数(开始下标结束下标)包左不包右split()字符串方法把字符串切割成数组不修改原字符串7. Array.sort() 排序坑点不传回调函数默认按字符串字典ASCII排序数字排序错乱11排在2前面数字升序arr.sort((a,b)a-b)数字降序arr.sort((a,b)b-a)会直接修改原数组8. 数组遍历方法有哪些区别forEach普通遍历不能break终止map遍历并返回新数组多用于数据加工filter筛选数组返回符合条件的新数组find查找第一个符合条件的元素every/some判断数组全部/部分元素是否符合条件9. 数组哪些方法修改原数组修改push、pop、shift、unshift、splice、sort、reverse不修改slice、map、filter、concat三、作用域变量提升10. var、let、const 的区别作用域var 没有块级作用域let、const 有块级作用域大括号内部失效变量提升var 会变量提升let、const 不会重复声明var可以重复定义let、const不能重复声明常量const 不能修改栈内存的值引用类型内部属性可以修改11. 什么是变量提升JS代码执行前浏览器会把 var定义的变量、函数声明提前提升到当前作用域最顶部缺点容易出现变量泄露、逻辑混乱所以现在全部禁用var用let/const12. 什么是暂时性死区let/const专属块级作用域内变量声明之前不能使用这个变量这段区间就是暂时性死区13. 闭包是什么作用和缺点内部函数调用外部函数的变量就形成闭包作用1. 实现私有变量2. 延长局部变量生命周期缺点变量常驻堆内存容易造成内存泄漏四、执行上下文事件循环14. JS 执行机制是什么JS是单线程同一时间只能做一件事设计初衷JS 要操作 DOM。 如果多线程同时改页面元素会出现冲突一个线程删按钮、一个线程改按钮浏览器不知道以谁为准。所以规定所有 DOM 操作、JS 代码都交给唯一主线程执行同一时刻只能执行一段代码。JS 靠什么实现 “看起来同时执行”事件循环并发实现原理核心把任务分成三类排队轮流执行快速切换视觉上并行。同步代码主线程立刻执行优先全部做完微任务同步完一次性清空所有微任务宏任务一次只取一个再回去处理微任务JS 真正能做到并行的方案主线程依旧单线程但是浏览器提供额外线程实现真正并行Web Worker单独开辟一条独立线程和主线程并行运行用来处理大量计算、大数据循环不会阻塞页面 DOM 渲染。 限制Worker 不能操作 DOM只能和主线程通过消息通信。浏览器底层线程浏览器多线程JS 主线程只是其中一条GUI 渲染线程绘制页面HTTP 请求线程发 ajax、接口请求并行发起多个请求定时器线程管理 setTimeout 这些线程是浏览器提供的不属于 JS 主线程所以多个网络请求可以并行发送。15. 宏任务和微任务区别事件循环执行顺序先执行同步代码再执行全部微任务promise.then、async/await、queueMicrotask最后执行宏任务setTimeout、setInterval、ajax一轮循环结束重复执行16. async 和 promise 了解吗通俗讲都是解决回调地狱异步编程方案async/await 是promise的语法糖写法更简单五、this指向17. this 的指向规则谁调用this就指向谁普通函数直接调用非严格模式指向window严格模式指向undefined对象调用函数指向调用函数的对象箭头函数没有自己的this继承上层作用域的thisdom事件绑定指向绑定事件的dom元素18. call、apply、bind 区别共同点修改函数this指向call参数逐个传入立即执行apply参数数组传入立即执行bind修改this返回新函数不会立即执行六、原型继承19. 原型和原型链是什么JS所有对象都有__proto__原型属性指向公共原型对象一层层往上查找原型形成的链条就是原型链用来实现方法复用节省内存20. constructor、prototype、__proto__ 关系构造函数有prototype实例对象有__proto__两个互相指向constructor指向构造函数七、拷贝问题21. 浅拷贝和深拷贝区别浅拷贝只拷贝第一层属性内层引用类型还是共用堆内存修改互相影响深拷贝拷贝全部层级数据开辟全新堆内存两个数据完全互不影响简单深拷贝方案JSON.parse(JSON.stringify(obj))八、浏览器内存相关22. 什么是内存泄漏JS常见场景JS 有垃圾回收机制 GC会自动找出没有任何变量引用、再也用不到的数据把堆内存释放掉。 内存泄漏指一段代码逻辑已经彻底用完、不会再使用的数据却依然被变量持有引用GC 识别不到无法回收这块堆内存。 随着页面长时间运行泄漏的数据越堆越多堆内存持续上涨出现页面卡顿、动画掉帧、切换页面变卡严重时浏览器标签页崩溃。内存泄漏无用数据占用堆内存浏览器无法回收页面卡顿崩溃常见场景全局变量过多、闭包、定时器未清除、dom引用未清空23. 栈溢出和堆溢出区别栈溢出StackOverflow递归死循环、函数嵌套过多栈内存空间不足栈容量是固定有限的函数调用层级过多栈帧堆满。无限递归一直调用自身不断创建栈帧没有终止条件几百上千层函数嵌套调用。报错RangeError: Maximum call stack size exceeded和堆内存无关只是栈空间耗尽程序直接卡死抛出错误不会缓慢卡顿一运行直接报错堆溢出OOM大量对象不销毁堆内存占满堆中创建大量对象、大数据并且存在引用无法 GC 回收堆内存被占满。来源一般是持续内存泄漏全局变量、闭包、定时器、未释放 DOM 不断堆积数据。不会立刻报错是缓慢恶化页面越用越卡内存占用持续走高浏览器任务管理器内存只涨不跌内存耗尽后浏览器直接崩溃、标签页闪退。九、前端手撕简答1. 手写数组去重最简最优方案ES6代码最短// 原理Set集合不允许重复元素 function uniqueArr(arr) { return [...new Set(arr)] } // 测试 console.log(uniqueArr([1,2,2,3,3,1])) // [1,2,3,1]面试口述讲解利用ES6 Set数据结构天然去重扩展运算符转为数组代码最少、性能最好日常开发和面试首选缺点无法去除引用类型重复。2. 手写简单深拷贝适配普通对象、数组满足90%面试场景不用递归复杂边界// 简单版深拷贝 function deepClone(obj) { if(typeof obj ! object || obj null){ return obj } // 判断数组/普通对象 let newObj Array.isArray(obj) ? [] : {} // 遍历赋值所有属性 for(let key in obj){ if(obj.hasOwnProperty(key)){ // 不拷贝原型上的属性 newObj[key] deepClone(obj[key]) } } return newObj }面试口述讲解递归遍历对象基本类型直接返回引用类型新建内存空间逐层拷贝所有层级属性新旧数据完全隔离互不影响。深拷贝JSON.parse(JSON.stringify(obj))缺点无法拷贝函数、undefined3. 手写节流、防抖先背概念防抖频繁触发事件停止触发后 n 秒才执行一次输入框搜索、弹窗关闭节流频繁触发事件固定间隔 n 秒只能执行一次滚动页面、窗口缩放、按钮频繁点击### ① 手写防抖 // 防抖函数 function debounce(fn, delay) { let timer null return function(...args) { clearTimeout(timer) // 频繁触发清空定时器 timer setTimeout(() { fn.apply(this, args) timer null }, delay) } } ### ② 手写节流时间戳版最简 // 节流函数 function throttle(fn, delay) { let lastTime 0 return function(...args) { let now Date.now() // 间隔达标才执行函数 if (now - lastTime delay) { fn.apply(this, args) lastTime now } } }4. 解释 LRU 缓存前端应用1、定义LRU是最近最少使用缓存淘汰策略缓存容量满了之后自动剔除最久没有访问的数据保留高频访问数据。2、底层实现哈希表 双向链表哈希表快速查询双向链表维护访问顺序头部存最近访问数据尾部存最少访问数据。3、前端实际工程应用浏览器本地缓存、页面内存缓存管理前端接口结果缓存重复请求直接读缓存减少服务器压力大模型前端上下文缓存限制上下文长度淘汰老旧无用对话框架内部组件缓存Vue keep-alive 底层就是LRU算法