JS学习与简单复盘

学习资料:学习JavaScript这一篇就够了-CSDN博客

一、JS 基础语法

1. JS的数据类型有哪些?怎么分类?

通俗标准答案

一共7种,分为两大类:

  1. 基本数据类型(简单类型/值类型):string、number、boolean、undefined、null、symbol

  2. 引用数据类型(复杂类型):object(数组Array、函数Function、普通对象都属于Object)

核心区别

  • 基本类型:存在栈内存,赋值是拷贝本身的值,互不影响

  • 引用类型:变量存内存地址,真实数据存在堆内存;赋值只拷贝地址,两个变量会互相影响

2. null 和 undefined 的区别?

通俗直白答案

  • undefined系统自动赋值,定义了变量但是没给值、函数无返回值、对象不存在的属性,默认都是undefined

  • null开发者手动赋值,代表空对象、手动清空变量;

面试一句话总结:undefined是不知道是什么,null是空对象;typeof null 结果是object(JS历史bug)

3. == 和 === 的区别?

必考标准答案

  • == 弱相等 :只比较值,会自动隐式类型转换,转换成相同类型再对比

  • === 强相等(严格相等) :先对比数据类型,类型不一样直接false;类型相同再对比值,不做类型转换

经典面试特例:null == undefined 结果为true;null === undefined 为false

4. JS 隐式类型转换规则?

大白话总结:运算、== 判断的时候,JS自动帮你转类型

  1. 字符串+数字:数字转字符串,做拼接

  2. 减乘除、大小比较:字符串转数字

  3. 布尔判断:0、''、null、undefined、NaN 为 false;其余全是true

5. typeof 能判断哪些类型?缺点是什么?

typeof 判断结果:string/number/boolean/undefined/symbol/function/object


二、数组高频八股

6. splice、slice、split 三个方法区别?

小白最简单背诵版

  1. splice()修改原数组;删除/新增/替换数组元素,参数:(起始下标,删除个数,新增元素)

  2. slice()不修改原数组;截取数组/字符串,参数(开始下标,结束下标),包左不包右

  3. 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 的区别?

  1. 作用域 :var 没有块级作用域;let、const 有块级作用域(大括号内部失效)

  2. 变量提升:var 会变量提升;let、const 不会

  3. 重复声明:var可以重复定义;let、const不能重复声明

  4. 常量:const 不能修改栈内存的值;引用类型内部属性可以修改

11. 什么是变量提升?

JS代码执行前,浏览器会把 var定义的变量、函数声明,提前提升到当前作用域最顶部;

缺点:容易出现变量泄露、逻辑混乱;所以现在全部禁用var,用let/const

12. 什么是暂时性死区?

let/const专属:块级作用域内,变量声明之前,不能使用这个变量,这段区间就是暂时性死区

13. 闭包是什么?作用和缺点

内部函数调用外部函数的变量,就形成闭包

作用:1. 实现私有变量;2. 延长局部变量生命周期

缺点:变量常驻堆内存,容易造成内存泄漏


四、执行上下文&事件循环

14. JS 执行机制是什么?

JS是单线程:同一时间只能做一件事

设计初衷:JS 要操作 DOM。 如果多线程同时改页面元素,会出现冲突:一个线程删按钮、一个线程改按钮,浏览器不知道以谁为准。

所以规定:所有 DOM 操作、JS 代码都交给唯一主线程执行,同一时刻只能执行一段代码。

JS 靠什么实现 "看起来同时执行"?事件循环(并发实现原理)

核心:把任务分成三类,排队轮流执行,快速切换,视觉上并行。

  1. 同步代码(主线程立刻执行,优先全部做完)
  2. 微任务(同步完一次性清空所有微任务)
  3. 宏任务(一次只取一个,再回去处理微任务)

JS 真正能做到并行的方案

主线程依旧单线程,但是浏览器提供额外线程,实现真正并行:

  1. Web Worker 单独开辟一条独立线程,和主线程并行运行,用来处理大量计算、大数据循环,不会阻塞页面 DOM 渲染。 限制:Worker 不能操作 DOM,只能和主线程通过消息通信。
  2. 浏览器底层线程(浏览器多线程,JS 主线程只是其中一条)
    • GUI 渲染线程:绘制页面
    • HTTP 请求线程:发 ajax、接口请求(并行发起多个请求)
    • 定时器线程:管理 setTimeout 这些线程是浏览器提供的,不属于 JS 主线程,所以多个网络请求可以并行发送

15. 宏任务和微任务区别?事件循环执行顺序

  1. 先执行同步代码

  2. 再执行全部微任务(promise.then、async/await、queueMicrotask)

  3. 最后执行宏任务(setTimeout、setInterval、ajax)

  4. 一轮循环结束,重复执行

16. async 和 promise 了解吗?

通俗讲:都是解决回调地狱,异步编程方案;async/await 是promise的语法糖,写法更简单


五、this指向

17. this 的指向规则

谁调用,this就指向谁

  1. 普通函数直接调用:非严格模式指向window;严格模式指向undefined

  2. 对象调用函数:指向调用函数的对象

  3. 箭头函数:没有自己的this,继承上层作用域的this

  4. dom事件绑定:指向绑定事件的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,代码最短)

复制代码
javascript 复制代码
// 原理: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%面试场景,不用递归复杂边界

javascript 复制代码
// 简单版深拷贝
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 
}

面试口述讲解:递归遍历对象;基本类型直接返回,引用类型新建内存空间;逐层拷贝所有层级属性;新旧数据完全隔离互不影响。

深拷贝:

javascript 复制代码
JSON.parse(JSON.stringify(obj))

缺点:无法拷贝函数、undefined

3. 手写节流、防抖

先背概念

  • 防抖:频繁触发事件,停止触发后 n 秒才执行一次;输入框搜索、弹窗关闭

  • 节流:频繁触发事件,固定间隔 n 秒只能执行一次;滚动页面、窗口缩放、按钮频繁点击

javascript 复制代码
### ① 手写防抖

// 防抖函数
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算法)

相关推荐
云浪2 小时前
拆开 WAV,看见声音——JavaScript 二进制数组实战全解析
前端·javascript·ecmascript 6
想你依然心痛2 小时前
嵌入式日志系统:分级日志、环形缓冲区与远程输出——运行时调试、非侵入
android·前端·javascript
夜郎king2 小时前
RuoYi-Vue3 企业级后台快速落地实战指南
java·开发语言
这是个栗子2 小时前
【Vue代码分析】 import.meta.env.DEV:现代前端工程中的环境变量
前端·javascript·vue.js·环境变量
像牛奶却不是牛奶2 小时前
记录几个前端实用小函数
前端·javascript
江华森2 小时前
exp01_Python_数据类型
开发语言·python
希冀1232 小时前
【JavaScript】Javascript—JS进阶—Day03
开发语言·javascript·原型模式
gugucoding3 小时前
28. 【C语言】通用数据操作:`void *` 与类型无关编程
c语言·开发语言
曹牧3 小时前
XML 解析过程中遇到 `org.xml.sax.SAXParseException
java·开发语言
光影少年3 小时前
RN 架构:JS层、原生桥接层、原生渲染层 通信原理
开发语言·javascript·架构