JavaScript 知识点整理

1. 什么是AST?它在前端有哪些应用场景?

AST Abstract Syntax Tree抽象语法树,用于表达源码的树形结构

应用:

  • Babel:一个广泛使用的 JS 编译器,将ES6+ 或 JSX 等现代语法转换为兼容性较好的 ES5 代码。
  • Eslint:JS 静态代码分析工具,它基于 AST 来分析代码中潜在问题和违反的代码规范。
  • Terser:JS 压缩工具,使用 AST 进行代码压缩和混淆
  • webpack 和 Rollup:构建工具使用AST 来优化 JS 和其他前端资源的打包过程。

AST 是前端开发中处理代码、优化构建、提高代码质量和实现跨语言支持的核心工具之一。它帮助前端工具深入理解代码结构,从而对代码进行高效的转化、优化和分析。通过AST,前端开发者能够更加轻松地进行代码转换、静态检查、压缩和混淆等操作,从而提高效率和应用性能。

2.中序遍历、前序遍历、后续遍历

在这里插入图片描述

前序遍历:根左右 ABDECFG
中序遍历: 左根右 DBEAFCG
后序遍历:左右根 DEBFGCA

3.什么是 BFF,它又有什么用?

BFF (Backend For Frontend)是一种架构模式,专门为前端应用提供定制化的后端服务。它的核心思想是为不同的前端客户端(如web、移动端、桌面端等)提供专门的后端服务,而不是让所有的客户端共享一个通用后端API

用途:
1)优化前端性能:

  • 减少请求次数:BFF 可以将多个后端API的请求合并为一个,减少前端请求的次数。
  • 减少数据传输量:BFF 可以根据前端的需求,对后端返回的数据进行聚合、过滤或转换、减少不必要的数据传输。

2)解耦前端和后端

  • 独立开发
  • 灵活适配:BFF可以根据不同的客户端(web、移动端)提供不同的API,而不需要修改后端服务

3)统一安全控制
在 BFF 层集中处理身份验证、权限管理、请求限流等安全策略,避免分散到各个微服务。

4)缓存与容错:缓存高频访问数据(如用户信息),减少后端压力。实现重试、熔断等机制。增强系统容错性

4.同一个url地址,如何实现手机打开是移动端页面,电脑打开是web页面

  1. 流体布局: 100% 、相对单位rem、 flex、grid
  2. 媒介查询(media query):一套代码
    css 判断(@media),js逻辑(matchMedia)
    存在问题: 1.差异化越大,开发维护成本越大;2.打包体积(PC + Mobile)
    结论:适合差异化较小的站点
  3. 服务器判断请求头:user-agent :独立开发、分开开发、独立部署

5.当 QPS 达到峰值是,该如何处理?

  • 缓存:本地缓存、服务器缓存、CDN 预热…
  • 减少请求:合并请求、雪碧图…
  • 延时请求: 懒加载…
  • 扩容
  • 数据库优化:sql优化、索引、读写分离
  • 负载均衡
  • 监控报警

6 如何实现精确的setInterval?

1.根据 performance.now 动态补偿
2.优先使用 requestAnimationFrame 替代定时器,与屏幕刷新率同步(约 16.67ms/帧)【不受失活页面影响,受很多其他因素影响】
3.webworker 【不受失活页面影响,不受渲染帧的影响】

7.页面上有100万个任务需要执行,如何保证页面不卡顿

  1. 任务分批处理: requestAnimationFrame 或者 setTimeout 实现异步调度
  2. requestIdleCallback:在浏览器空闲时执行低优先级任务;
  3. Web Workers:将计算密集型任务移到其他线程:【缺陷:1.无法直接操作 DOM;2.线程间通信(postMessage)有性能开销,需减少数据传递频率】

8.死循环会导致什么后果?无限递归会导致什么后果?

死循环:页面卡顿、无响应
无线递归: 堆栈溢出、程序崩溃

9.后端响应巨量数据,前端如何避免其性能问题?

减少主线程负载,分而治之。优先通过流式传输、分页、Worker多线程减轻数据压力,再结合虚拟化、Canvas等渲染优化提升用户体验。

  1. 网络性能:
    1. 改接口规格
    2. sse( server sent event ) / websocket 实时推送
    3. 流式读取: etch stream
  const resp = await fetch("XXXX");//等待响应头到达
  const body = await resp.json();//等待响应体
  1. 渲染性能:
  • 分页(产品参与协调)
  • 分片渲染 (React Fiber)
  • 虚拟滚动
  • canvas

10.vue 项目有哪些常见的优化手段?

  • 图片懒加载、路由懒加载

  • suspence 【用于管理异步操作(如数据加载、代码分割)的组件】

  • v-if 和 v-show

  • 打包手段优化

  • 网络手段优化

    • CDN (公共库)
    • http2
    • 图片格式优化
    • gzip
    • 请求合并
    • GraphQL
  • key

  • computed

  • 保持对象地址的稳定性

  • 延迟装载

  • v-model lazy 延时双向绑定

  • 冻结对象(vue2)

  • 函数式组件(vue2)

11. isNaN 和 Number.NaN 的函数区别?

isNaN 和 Number.isNaN 是 JavaScript 中用于判断 NaN (Not-a-number)的函数。
isNaN 接收参数后,会尝试将这个参数转换为数值,任何不能被转换为数值的值都会返回 true,isNaN(‘true’) === true;
Number.isNaN 会首先判断传入的参数是否是数字,如果是数字再继续判断是否 NaN。

12. Map和object的区别?

MapObject
构造方式new Map()创建通过字面量、new Object()、Object.create()等方式创建
键的类型Map的键可以是任意类型,包括对象、数组、函数等只能是字符串或者Symbol,其他类型的键会被转换为字符串
键的顺序有序无序
键值大小使用 .size 属性来获取其大小。使用 .get() 方法获取值。没有内置的方法来获取其大小(键值对的数量)采用Object.keys(xxx).length获取大小。使用 . 获取值。
原型继承不会从原型链中继承属性会从原型链中继承属性
迭代可以直接迭代获取到键值后才能迭代
性能在频繁添加和删除键值对性能更好在频繁添加和删除键值对未作出优化

13. map和weakMap的区别?

MapweakMap
键的类型可以使用任何类型的值作为键,包括原始类型(如字符串、数字)和对象。只能使用对象作为键
垃圾回收机制键是 强引用。即使键对象已无其他引用,只要 Map 存在,该对象仍不会被垃圾回收,可能导致内存泄漏。键是 弱引用。当键对象无其他引用时,垃圾回收机制会自动回收该键及其关联的值,避免内存泄漏。
迭代和操作支持 遍历操作(如 forEach、for…of),可通过 keys()、values()、entries() 获取迭代器。内置 size 属性,可获取键值对数量。不支持遍历,无 size 属性,也无法直接获取所有键值对。设计初衷是保护键对象的隐私和自动清理,因此不暴露遍历接口。

14. JavaScript 标准内置对象

  1. 基本对象
    构成 JavaScript 的核心基础,用于定义其他对象或行为:
    • Object:所有对象的基类,提供属性操作(如 hasOwnProperty())
    • Function:函数的构造器,每个函数都是其实例
    • Boolean 和 Symbol:分别表示布尔值和唯一符号的包装器
  2. 处理特定类型的数据:
    • String:字符串操作(如 charAt()、replace())
    • Number 和 BigInt:数值类型,后者支持大整数运算
    • Boolean:布尔值的包装类型(注意与基本类型的 true/false 区分)
  3. 集合与数据结构
    存储和管理数据集合:
    • Array:有序元素集合,支持动态操作(如 push()、map())
    • Map 和 Set:键值对集合与唯一值集合
    • WeakMap:弱引用键值对,避免内存泄漏
  4. 错误处理对象
    捕获和管理运行时错误:
    • Error:基础错误类型
    • 子类:TypeError(类型错误)、SyntaxError(语法错误)、ReferenceError(引用错误)等 。
  5. 数学与日期对象
    处理数学运算和日期时间:
    • Math:提供数学函数(如 Math.random())和常量(如 Math.PI)
    • Date:解析和计算日期时间(如 getFullYear())
  6. 其他功能对象
    扩展语言能力的关键对象:
    • JSON:数据序列化与解析(JSON.stringify()、JSON.parse())
    • RegExp:正则表达式,用于字符串模式匹配
    • Promise:管理异步操作
    • Proxy:对象代理,支持元编程(如拦截对象操作)
  7. 全局属性与函数
    全局作用域下的属性和工具函数:
    • 值属性:Infinity(无穷大)、NaN(非数字)、undefined
    • 全局函数:eval()(执行字符串代码)、parseInt()(字符串转整数)、isNaN()(判断非数字)

15.数组有哪些原生方法

方法作用是否影响原数组
push在数组后添加元素,返回长度
pop删除数组最后一项,返回被删项
shift删除数组第一项,返回删除项
unshift数组开头添加元素,返回长度
reserve反转数组,返回数组
sort排序数组,返回数组
splice截取数组,返回被截取部分
join将数组变成字符串,返回字符串
concat连接数组
map相同规则处理数组项,返回新数组
forEach遍历数组
filter过滤数组项,返回符合条件的数组
every每一项符合规则才返回 true
some只要有一项符合规则就返回 true
reduce接收上一个 return 和数组下一项
flat数组扁平化
slice截取数组,返回被截取区间

16.Unicode、UTF-8、UTF-16、UTF-32的区别?

17.escape、encodeURI、encodeURIComponent的区别

方法编码对象编码范围编码规则兼容性
escape字符串除 ASCII字母、数字、@*/+ 外的字符均编码为 %XX 或 %uXXXX(Unicode编码)直接对字符的Unicode编码加 %u 前缀,仅支持ASCII字符(≤255),已过时且不推荐使用不适用于URL,仅旧环境兼容
encodeURI完整URL保留URL合法字符(如 😕?#[]@ 等),仅编码空格、中文等非法字符为 %XX将非法字符转换为UTF-8字节后编码,保持URL结构完整适用于编码整个URL
encodeURIComponentURL组成部分(如参数)编码范围更广,包括 😕?# 等保留字符,仅保留 !*()’ 和基本ASCII字符对字符进行更严格编码,确保参数值安全传输,常用于拼接查询字符串适用于URL参数或路径片段

18. JavaScript为什么要进行变量提升,它导致了什么问题?

变量提升是JavaScript早期设计中的权衡产物,虽然提升了性能和容错性,但也带来了作用域混乱、变量污染等问题。现代开发中,应优先使用let/const,并通过规范代码结构规避潜在风险

19. ESM 和 CommonJS 有什么区别?

ESMCMJ
标准来源官方标准(新增语法)社区标准(新增API)
导入机制静态声明依赖,模块关系在编译时确定,支持 Tree Shaking 优化动态加载,模块运行时动态生成,灵活性高
加载机制编译时静态分析依赖,支持异步加载运行时同步加载,阻塞后续代码执行
动态加载支持 import 动态导入(返回 Promise)直接使用 require()动态加载
作用域块级作用域,严格模式(this 为 undefined)共享全局作用域,可能污染变量

20.use strict 是什么意思 ? 使用它区别是什么?

是 JavaScript 中用于启用 严格模式(Strict Mode) 的指令,由 ECMAScript 5(ES5)引入。其核心目的是通过更严格的语法和运行时检查,减少代码中的潜在错误,提升安全性及性能。
区别:

  • 构造函数必须使用 new;
  • 变量必须声明
  • 禁止使用eval、 with 语句;
  • 禁止 this 关键字指向全局对象;
  • 对象不能有重名的属性;
    优势:
  • 消除静默错误:将隐式错误转为显式报错,提升代码健壮性
  • 提高安全性:限制危险操作(如 eval、with),减少漏洞风险
  • 优化性能:静态分析支持编译器优化(如 Tree Shaking)

21.for…in和for…of的区别

for…infor…of
迭代对象遍历对象的可枚举属性(包括继承的属性),适用于普通对象、数组(但不推荐)遍历可迭代对象(如数组、字符串、Map、Set等),要求对象实现 Symbol.interator接口
迭代内容返回键名返回值
遍历顺序不确定(对象属性无固定顺序)确定(按可迭代对象的顺序,如数组索引顺序)
兼容性ES6+
性能会检查原型链,性能较低对数组的遍历效率接近 传统 for 循环

22. Html 5 有哪些特性

  1. 语义化标签: header、footer、nav、section、article、aside
  2. 增强型表单: date、email、number、range、search、tel 等
  3. 视频和音频: audio、video
  4. Canvas 绘图、SVG 绘图
  5. 地理定位: Geolocation
  6. 拖放: drag
  7. web Workers: 是运行在后台的 Javascript ,独立于其他脚本,不会影响页面性能
  8. web storage: localStorage、sessionStorage
  9. webSocket: HTML5 开始提供一种在单个 TCP 连接上进行全双工通讯的协议

23. 如何实现浏览器内多个标签页之前的通信

场景推荐方案关键考量
同源简单数据同步LocalStorage兼容性优先,数据量小
同源实时通信Broadcast Channel低延迟,API简洁
跨域通信window.postMessage跨域需求,安全验证
复杂计算与资源共享ShareWorker高性能,长期任务处理
高并发实时应用WebSocket服务端支持,低延迟。 [支持跨域]
离线与后台消息Service Worker离线场景,消息中转

总结:

  • 明确支持跨域:Window.postMessage、WebSocket
  • 间接支持跨域:Service Worker(需其他技术辅助)
  • 仅在同源:localStorage、Broadcast Channel 、ShareWorker

24. HTML5 离线缓存

基于一个manifest 文件( 缓存清单文件,后缀为 .appcache ) 的缓存机制(不是存储技术)
主要通过 html 元素的 manifest 属性指定一个后缀为 manifest 的文件,该文件为网页指定哪些文件需要被缓存,哪些不需要缓存,已经获取失败的处理方式等等。

25. FCP 和 LCP 区别?

FCP(First Contentful Paint)和LCP(Largest Contentful Paint)是衡量网页加载性能的两个关键指标,它们的核心区别在于 关注的内容阶段和用户体验的维度不同

维度FCP【First Contentful Paint】LCP【Largest Contentful Paint】
测量元素首个文本、图片、Canvas 等任意内容视口内最大的图片、视频、背景图或者大段文本块
元素重要性可能包含非关键内容(如加载动画)聚焦用户关注的“核心内容”
动态变化仅记录第一次内容渲染页面加载过程中可能多次更新(最大元素变化时)
用户交互影响不受用户操作影响用户首次滚动或者输入后停止记录
性能标准无固定阈值,但建议控制在 1s 以内,以提升用户对加载速度的感知理想值为 2.5 s内,超过则视为影响用户体验

26. 说一说 JS 垃圾回收机制?

  1. 什么是垃圾

    • 定义:程序中不再被引用的变量或对象,例如函数执行后未被外部引用的局部变量
    • 生命周期
      • 全局变量:持续到页面关闭
      • 局部变量:函数执行后即可被回收,除非被闭包或外部引用保留
  2. 为什么需要垃圾回收
    Javascript 动态分配内存的特性(如变量、对象、函数的创建)可能导致内存泄漏,长期积累会导致程序性能下降甚至崩溃

垃圾回收的核心算法

  1. 引用计数法

    • 原理:记录每个对象的引用次数,当引用次数归零时回收内存
    • 实例
      let objA = {};  // 引用计数为1  
      let objB = objA; // 引用计数为2  
      objA = null;     // 引用计数为1  
      
    • 缺陷:无法处理循环引用(如两个对象互相引用),导致内存泄漏
  2. 标记清除法

    • 原理
      • 标记阶段:从滚对象(全局变量、当前执行上下文)出发,标记所有可达对象
      • 清除阶段:释放未被标记的对象内存
    • 优点:解决循环引用问题,是现代浏览器的默认算法(如 Chrome V8 引擎)
    • 缺点:产生内存碎片,可能影响大对象的内存分配效率
  3. 标记整理法:

    • 优化点: 在标记清楚后,将存活对象移动到内存一端,消除碎片,提升内存连续性。

V8 引擎的优化策略

  1. 分代回收
    • 新生代:存放短生命周期对象(如临时变量),使用 Scavenge 算法(复制存活对象到新空间,快速回收)
    • 老生代:存放长生命周期对象(如全局变量),使用 标记-清除 + 标记-整理 组合算法
  2. 增量回收:将垃圾回收任务拆分为多个小步骤,穿插在代码执行中,减少主线程阻塞时间
  3. 并发回收:在后台线程执行垃圾回收,避免主线程卡顿

常见内存泄漏场景与预防

  1. 全局变量:

    • 实例:未使用 var/let/const 声明的变量意外成为全局变量
    • 解决:严格声明变量,及时置为 null
  2. 闭包:

    • 示例:函数内变量被闭包引用,导致函数执行后无法回收。
    • 解决:在闭包内不再使用时手动杰出引用
  3. 未清除的定时器与事件监听器

    • 示例:setinterval 或 DOM 事件未及时清理
    • 解决:使用 clearInterval 或者 removeEventlistener
  4. DOM 引用

    • 示例:保存已移除的 DOM 元素的引用,阻碍其内部释放
    • 解决: 移除 DOM 后置相关变量为 null

内存优化建议

  • 减少内存分配频率:重用对象或数组,避免频繁创建新对象
  • 使用弱引用:通过 WeakMap 或 WeakSet 避免强引用导致的内存保留
  • 监控工具:利用 Chrome DevTools 的 Memory 面板分析内存使用情况,识别泄漏点

Javascript 的垃圾回收机制通过自动管理内存,简化开发者工作,但其底层算法(如标记清除和分代回收) 仍需要开发者理解以避免内存泄漏。通过**合理编码习惯(如及时解除引用、使用弱引用)**和工具监控,可以有效优化内存使用。

27. 如何封装一个request?

一. 核心思路

  1. 代码复用性:避免每个请求重复编写基础配置(如超时、请求头、鉴权),统一管理请求逻辑
  2. 统一拦截与处理:通过拦截器集中处理错误、权限校验、数据格式转换等通用逻辑,提到代码可维护性
  3. 规范接口管理:模块化分类API,便于多人协作和后期扩展

二.进阶设计

  1. 取消重复请求:利用 Axios 的 CancelToken 或者 AbortController 终止重复/过时请求
  2. 请求重试机制:对网络错误或超市请求自动重试,提升用户体验
  3. 缓存与节流:对高频 Get请求添加缓存策略,减少服务器压力
  4. Typescript 支持:定义接口返回类型,增强代码健壮性

三. 总结

封装 Request 的核心在于标准化流程灵活扩展结合。通过拦截器实现统一逻辑,模块化提升可维护性同时结合团队规范(如错误码处理、日志上报)打造高可用请求层。【解决项目痛点(如鉴权失败、接口混乱等)】

28. 什么是 JWT ?

JWT (JSON Web Token)是一种基于开放标准(RFC 7519)的跨域认证和授权解决方案,其核心是通过 JSON 格式的令牌在各方之间安全传输信息。
定义:
JWT 是一种紧凑且自包含的令牌,由三部分组成:Header(头部)、Payload(荷载)和 Signature(签名),三者用点(.)连接,形如xxx.yyyy.zzzzz

  • Header:包含令牌类型(JWT)和签名算法(如HS256、RSA),经 Base64Url编码后形成第一部分
  • Payload:存储用户身份、权限等声明(Claims),分为注册声明(如 exp 过期时间)、公共声明和私有声明,同样经 Base64Url 编码
  • Signature:通过 Header 中指定的算法对 Header 和 Payload进行加密生成,用于验证数据完整性和来源真实性

应用场景:

  1. 用户授权:JWT 最常见的用途是身份验证。用户登陆后,后续请求携带 JWT令牌,服务器无需存储 Session 信息,特别适用无状态 RESTfull API 和单点登录(SSO)场景
  2. 信息交换:JWT 可通过 前面确保数据未被篡改,适用于服务传递用户上下文西信息(如 微服务架构中的权限验证)
  3. 分布式系统:由于 JWT 的无状态特性,服务端无需维护会话信息,可轻松实现跨域认证和高可用扩展性

工作原理
1. 生成与验证流程

  • 用户登录后,服务端生成 JWT 并返回客户端(通常存储在 LocalStorage 或 Cookie)
  • 客户端在请求头 Authorization: Bearer < JWT> 中携带令牌
  • 服务端验证签名有效性、过期时间等,通过后授权访问资源
    2. 签名机制 :使用密钥(HMAC 算法)或公钥私对(如 RSA) 对Header 和 Payload 进行加密,防令牌篡改。

JWT 优缺点

优点缺点
无状态:服务端无需存储会员,降低服务器压力不可撤销:令牌在有效期内无法强制失效,需依赖黑名单或短有效期
跨域友好:适用于前后端分离和微服务架构数据透明:Payload 内容可被 Base64 解码,需避免存储敏感信息
自包含性:减少数据库查询,提升性能密钥管理复杂:需安全存储签名密钥,防止泄漏

与传统 Session【token】认证对比

维度JWT传统 Token
结构组成三部分:Header(算法)、Payload(数据)、Signature(签名)通常为简单字符串(如 UUID),无固定结构
信息存储用户信息直接编码在 Payload 中,可包含角色、权限等元数据仅存储标识符(如 sessionID),需服务器关联数据库查询用户信息
验证方式通过密钥解密签名验证完整性,无需查库需查库验证 Token 有效性及关联的用户信息
无状态性服务端无需存储用户状态,适合分布式系统依赖服务端存储(如 Redis),扩展性受限
  • Session 认证:依赖服务器存储会话 ID,存在扩展性差、跨域限制和 CSRF 攻击风险
  • JWT 认证:令牌存储在客户端,无状态且支持跨域,但需处理令牌失效和密钥管理问题

29. 什么是 RESTful API?

RESTful API (Representational State Transfer API)是一种基于 REST 架构风格设计的 Web 服务接口,旨在通过标准的 HTTP 协议和统一的接口规范,实现资源的访问与操作。其核心思想是将网络中的资源(如用户、订单、商品等)抽象为 URL ,客户端通过 HTTP 方法(Get、Post、Put、Delete 等)对资源进行增删改查(CRUD)操作,并以 JSON、XML 等格式返回结果。
典型应用场景

  • 跨平台服务: 适用于 Web、移动端、Iot设备,通过标准化接口实现数据交互
  • 微服务架构:服务间通过 RESTful API 传递资源信息,降低耦合
  • 高频数据访问:结合缓存和负载均衡,提升系统吞吐量

RESTful API 通过 资源抽象和 HTTP 标准化,提供了一种简洁、高效且易用于扩展的接口设计范式,适用于现代分布式系统和高并发场景。其核心价值在于 降低系统耦合度提升开发协作效率

30. 闭包(Closure)有什么优缺点?

闭包是一个函数与其创建时所处词法环境的组合

优点:

  1. 变量保护与封装性

    • 作用域隔离:闭包允许函数访问外层作用域的变量,同时将这些变量封装在私有作用域中,避免全局变量污染。例如:通过闭包实现模块化代码,仅暴露必要接口
    • 创建私有成员: 通过闭包可以模拟私有变量和方法,增强代码安全性。例如:计数器,count 变量被闭包保护,外部无法直接修改
  2. 持久化状态管理

    • 跨调用保留状态: 闭包使函数内部的变量在外部函数执行后仍驻留内存,适合需要跟踪状态场景(如计数器、缓存)
  3. 灵活性与代码复用:

    • 延迟执行与高阶函数:闭包可延迟代码执行(如事件回调),或用于函数工厂(柯里化)。例如 makeAdder 函数通过闭包生成不同加法函数
    • 模块化开发:闭包将相关逻辑与数据封装为独立模块,提升代码可维护性。例如:isFirstLoad 函数管理传入值的唯一性
  4. 解决特定编程问题

  • 避免循环引用问题:在异步操作(如 setTimeout)中,闭包可捕获循环变量的当前值,解决索引值错误问题。例如,循环事件示例中,闭包通过立即执行函数保存循环变量 i 的 瞬时值。

缺点

  1. 内存泄漏风险

    • 变量常驻内存: 闭包导致外层函数变量无法被垃圾回收(GC),大量闭包可能引发内存泄漏,尤其在旧版 IE 浏览器中。例如,内部函数持续引用外部变量 counter,导致内存无法释放。
    • 解决方案
      • 及时释放无用闭包(如将闭包变量设置为null)
      • 使用弱引用(WeakMap)存储外部变量
  2. 性能损耗:

    • 作用链查找开销:闭包访问外部变量需逐级查找作用域链,可能影响性能。例如,高频调用的闭包函数在嵌套较深是性能下降显著
    • 内存占用增加:闭包需额外存储词法环境,内存消耗高于普通函数
  3. 调试与维护复杂度

    • 作用域链复杂性:多层闭包嵌套时,变量的来源和值可能难以追踪,增加调试难度。例如,循环闭包问题中,变量 item 的意外覆盖需要块级作用域(let )解决
    • 代码可读性降低:闭包的隐式依赖和状态管理可能使逻辑更隐晦,对新手不友好
  4. 意外副作用

    • 变量值被外部修改:闭包可能在外层函数之外改变其内部变量,若设计不当会导致不可预期行为。例如,未合理控制闭包对外部变量的修改权限

闭包是一把双刃剑,其优势在于灵活的状态管理和封装能力,但需警惕内存与性能问题。合理使用时,闭包能显著提升代码质量;滥用则可能导致维护灾难。

31. 控制对象属性为只读可通过多种方式实现?

一. Object.defineProperty :精确控制属性特性

通过属性描述符 writable 或 get 方法实现只读

const obj = {};
// 方式1:设置 writable 为 false
Object.defineProperty(obj, "readOnlyProp", {
    value: 42,
    writable: false,   // 不可修改
    configurable: false // 不可删除或重定义
});

// 方式2:仅定义 getter(无 setter)
Object.defineProperty(obj, "readOnlyProp", {
    get() { return 42; } // 不定义 set,赋值操作静默失败
});

特点:

  • 精准控制单个属性的读写行为
  • 非严格模式下赋值静默失败,严格模式下报错
  • configurable:false 可防止后续修改属性特性

二. Object.freeze:冻结整个对象

使所有属性对象不可修改、删除或新增

const obj = { prop: 100 };
Object.freeze(obj);
obj.prop = 200; // 修改无效(严格模式报错)

注意

  • 浅冻结,嵌套对象需递归冻结
  • 适用于需要一次性锁定多个属性的场景

三.Proxy 代理:拦截属性操作

通过代理的 set 陷阱拦截赋值行为

const obj = { readOnlyProp: 42 };
const proxy = new Proxy(obj, {
    set(target, prop) {
        if (prop === "readOnlyProp") {
            throw Error("此属性只读");
        }
        return Reflect.set(...arguments);
    }
});
proxy.readOnlyProp = 100; // 抛出错误

优势:

  • 灵活拦截多种操作
  • 支持动态条件控制(如某些属性可读性,某些只读)

四.访问器属性(getter/setter)

通过定义 get 方法但不定义 set ,或抛出错误

// 方式1:仅定义 getter
const obj = {
    get readOnlyProp() { return 42; }
};
obj.readOnlyProp = 100; // 静默失败

// 方式2:定义 setter 并限制
const obj = {};
Object.defineProperty(obj, "readOnlyProp", {
    get() { return 42; },
    set() { throw Error("禁止修改"); }
});

适用场景:

  • 动态计算属性值
  • 结合私有变量实现数据保护

五.类私有属性(#语法)

通过 # 前缀定义仅在类内部可访问的属性

class MyClass {
    #secret = 42;
    getSecret() { return this.#secret; }
}
const obj = new MyClass();
obj.secret; // undefined(外部无法访问)

特点:

  • 严格实现私有性,而非直接只读
  • 需通过类方法间接暴露只读访问

六.其他场景补充

  1. HTML 元素属性(input.readOnly )
// 正确设置只读(布尔属性只需存在,值无关)
document.getElementById("input").readOnly = true; 
  1. 闭包封装
const createReadOnly = () => {
    let value = 42;
    return { getValue: () => value };
};
const obj = createReadOnly();
obj.getValue(); // 42,无法直接修改

总结与选择建议

场景推荐方法
单个属性精确控制Object.definePropery
全对象冻结Object.freeze
动态拦截或复杂逻辑Proxy
动态计算或模块化封装getter/setter
DOM 元素属性控制element.readOnly
类内部私有属性保护# 语法

注意事项:

  • 严格模式:非严格模式下部分操作静默失败,建议启用严格模式以捕获错误
  • 性能:Proxy 和 递归 freeze 可能影响性能,需权衡使用
  • 兼容性:Proxy 和 # 语法需 ES6+ 环境支持

32.工程内如何修改npm 包里面的变量?

一.临时修改:直接编辑 node_modules (不推荐但快速)

二.补丁方案:使用 patch-package(推荐)

适用场景:需持久化修改且 兼容 npm/yarm 项目
实现步骤

  1. 安装工具
npm install patch-package --save-dev
  1. 修改 node_modules :直接修改目标包源码中的变量
  2. 生成补丁文件
npx patch-package package-name  # 生成 patches/package-name+version.patch
  1. 配置自动应用补丁:在package.json 中添加 postinstall 脚本:
"scripts": {
  "postinstall": "patch-package"
}
  1. 提交补丁文件:将 patches 目录提交到版本控制。优点
  • 修改可持续化,团队写作时自动同步补丁
  • 支持跨平台:注意:需锁定依赖版本,升级包版本后需重新生成补丁

三. Fork 源码 并发布私有包

适用场景:需要长期维护修改或扩展功能。
实现步骤:
1. Fork 原仓库:在 GitHub 等平台Fork 目标包源代码
2. 修改变量并提交:
3. 发布到 私有 registry
4. 工程中替换依赖

四. 代理模式(warpper)

**适用场景:**仅需覆盖少量变量或方法
实现方式:

  1. 创建代理模块
import originalPkg from 'original-pkg';

// 覆盖原包变量
originalPkg.targetVariable = 'new-value';

export default originalPkg;

2.在工程中引入代理

import pkg from './wrappers/package-wrapper';

优点:无需修改 node-modules,代码可读性高
缺点:不适用于深层嵌套的变量或者复杂逻辑

五.环境变量注入(动态配置)

适用场景:通过外部参数控制包行为
实现方式:

  1. 安装时传递参数
npm install --custom-var=value
  1. 包内读取环境变量
// 包源码中读取
const value = process.env.npm_config_custom_var;

注意:需原包支持动态配置,否则需结合其他方案修改源码

总结:方案选择指南

场景推荐方案工具链推荐
快速测试直接修改 node_modules所有包管理器
团队协作/持久化修复patch-packagenpm/yarn
长期维护或企业级私有化fork 源码所有包管理器
轻量级涵盖变量代理模式所有包管理器

注意:

  1. 修改第三方包可能违反其许可证协议,需确认合法性
  2. 优先提交 PR 或 Issue 给原仓库,推动社区修复

33. Preload 和 Prefetch?

维度PreloadPrefetch
核心目的当前页面关键资源加速未来导航资源预加载
加载时机立即高优先级加载空闲时低优先级加载
使用资源CSS、字体、核心脚本下一页 HTML、非关键脚本
缓存优先级
执行控制需显示调用需显示调用
页面跳转影响请求终止可能继续加载

最佳实践建议:

  1. Preload 用于关键路径资源:如首屏 CSS 和字体,通过 < link rel=“preload” as=“style”> 声明
  2. Prefetch 用于预测性加载:如用户可能访问得下一页资源,避免过早占用带宽
维度deferasyncPreloadPrefetch
核心目标延迟执行依赖 DOM 的脚本异步执行的独立脚本加速当前页面关键资源加载预加载未来可能需要的资源
加载优先级高(由 as 决定)
执行顺序按文档顺序无序不执行,需显示调用不执行,需显式调用
适用场景框架初始化、DOM 操作统计分析、广告脚本字体、首屏、CSS、核心脚本下一页 HTML、非首屏图片

34. JS 沙箱有哪些?

一.浏览器环境中的沙箱

  1. iframe 沙箱

    • 原理: 通过 < iframe> 的 sandbox 属性控制限制子页面的行为(如禁用脚本、表单提交等),结合 postMessage 通信机制实现数据交互
    • 特点
      • 天然隔离,支持权限精细化配置(如 allow-script、allow-same-origin)
      • 腾讯无界框架(Wujie )基于此实现,通过劫持 document 和 location 将子应用 DOM 渲染到主界面
    • 限制: 需配置复杂的安全策略(如 CSP),且无法直接访问主页面全局对象
  2. Proxy + with + Function

    • 原理: 利用 with 语句将代码作用域绑定到沙箱对象,通过 Proxy 拦截属性访问,防止逃逸到全局环境
    • 实例:
      function createSandbox(code, sandbox) {
        const fn = new Function('sandbox', `with(sandbox) { return (${code}) }`);
        const proxy = new Proxy(sandbox, {
          has: () => true, // 欺骗代码,使其认为所有属性已存在
          get: (target, key) => key === Symbol.unscopables ? undefined : target[key]
        });
        return fn(proxy);
      }
      
    • 优点: 轻量级,适用于动态执行简单脚本
    • 缺点: 可能被 Symbol.unscopables 绕过,需额外处理
  3. shadowRealm 提案

    • 原理: ECMAScript 新提案,提供独立的全局作用域,内置对象与原环境隔离
    • 特点
      • 标准化的沙箱机制,支持模块化加载
      • 目前浏览器支持有限,尚未广泛应用

二. Node.js 环境的沙箱

  1. vm 模块

    • 原理: Node.js 内置模块,通过创建独立的上下文(context)隔离代码
    • 示例
      function createSandbox(code, sandbox) {
        const fn = new Function('sandbox', `with(sandbox) { return (${code}) }`);
        const proxy = new Proxy(sandbox, {
          has: () => true, // 欺骗代码,使其认为所有属性已存在
          get: (target, key) => key === Symbol.unscopables ? undefined : target[key]
        });
        return fn(proxy);
      }
      
    • 缺点:易通过原型链逃逸(如 this.constructor.constructor(‘return process’)() 获取 process 对象)
  2. vm2 模块

    • 原理: 基于 vm 模块增强,使用 Proxy 和 eval 隔离全局对象,拦截危险操作(如 require)
    • 特点:
      • 禁止访问 process 、fs等 敏感模块
      • 支持异步代码超时控制,安全性显著高于 vm
    • 示例:
      const { VM } = require('vm2');
      new VM().run('this.constructor.constructor("return process")()'); // 抛出异常
      
  3. Safeify
    第三方库:针对 Node.js 设计,结合进程隔离和资源限制,防止恶意代码导致内存泄漏或崩溃

三.特定场景的沙箱

  1. 小程序容器技术

    • 原理:在微信、支付宝等平台中,通过封闭的运行环境和权限控制(如限制网络请求、文件读写)保护宿主应用安全
    • 代表方案
      • 微信小程序:使用 WebView 隔离 + 自定义 API 白名单
      • FinClip:支持私有化部署的小程序容器,提供跨平台(IOS/Android/Windows)沙箱环境
  2. Web Worker

    • 原理:在独立线程中运行脚本,无法访问 DOM 和主线程全局变量
    • 限制:仍可调用部分 API (如 fetch ),需配合 CSP 增强安全

总结:
JS 沙箱的选择需根据场景权衡安全性与性能:
- 简单脚本:浏览器中可用 Proxy + with ,Node.js 优先选择 vm2
- 复杂隔离需求:浏览器用 iframe,Node.js 考虑 Safeify 或容器化(如 Docker)
- 企业级应用:小程序容器或自研沙箱框架(如腾讯无界)

35.HTML 中的 < meta> 标签?

HTML 中的 < meta>标签用于定义文档的元数据(metadata ),提供与页面相关的隐藏信息,如字符编码、页面描述、关键词、视口设置等

一、基础属性与常见用法

  1. 字符编码声明:通过charset 属性指定文档字符编码,确保多语言正确显示

    <meta charset="UTF-8"> <!-- HTML5 推荐写法 -->  
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <!-- 旧版兼容写法 -->  
    

    作用:定义页面使用的字符集(如 UTF-8、GBK)

  2. 页面描述与 SEO 优化

    • description :提供页面内容的简短描述,影响搜索引擎结果页(SERP)的展示

      <meta name="description" content="关于 HTML meta 标签的详细指南">  
      
    • keywords: 列出与页面相关的关键词(现代搜索引擎对其以来降低,但仍可用于某些场景)

      <meta name="keywords" content="HTML, meta标签, 前端开发">  
      
    • author :声明作者

      <meta name="author" content="张三">  
      
    • robots :控制搜索引擎爬虫行为,如禁止索引或跟踪链接

      <meta name="robots" content="noindex, nofollow"> <!-- 阻止索引和跟踪 -->  
      
    • 最佳实践:description 建议控制在 150 字符内,keywords 避免堆砌

二.浏览器兼容与渲染控制

  1. 视口(Viewport)设置
    针对移动端适配,定义可视区域宽度、缩放比例等
    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">  
    
  • 参数说明:
    • width=device-width:视口宽度与设备屏幕一致
    • inital-scale=1.0 :初始缩放比例为 1
    • maximum-scale=1.0 : 禁止用户手动放大
  • **作用:**确保页面在移动端上自适应显示
  1. IE 兼容模式:强制 IE 浏览器使用最新渲染引擎

    <meta http-equiv="X-UA-Compatible" content="IE=edge">  
    

    扩展:若需支持 Chrome Frame 插件(已弃用),可添加 chrome=1

三.HTTP 指令模式(http-equiv)

  1. 页面刷新与重定向:定时刷新或跳转到新页面

    <meta http-equiv="refresh" content="5; url=https://example.com"> <!-- 5秒后跳转 -->  
    

    应用场景: 临时维护页、旧域名迁移

  2. 缓存控制:设置页面过期时间或禁用缓存

    <meta http-equiv="expires" content="Mon, 12 May 2025 00:00:00 GMT"> <!-- 过期时间 -->  
    <meta http-equiv="pragma" content="no-cache"> <!-- 禁用本地缓存 -->  
    <meta http-equiv="cache-control" content="no-store"> <!-- 禁止缓存存储 -->  
    

    注意: 现代浏览器更依赖 HTTP 头部(如 Cache-Control),但 meta 标签可作为补充

四.高级应用与扩展协议

  1. 社交媒体优化(Open Graph/Twitter Cards) : 定义在社交平台分享时的标题、描述和缩略图:

    <!-- Open Graph 协议 -->  
    <meta property="og:title" content="页面标题">  
    <meta property="og:description" content="页面描述">  
    <meta property="og:image" content="https://example.com/image.jpg">  
    
    <!-- Twitter 卡片 -->  
    <meta name="twitter:card" content="summary_large_image">  
    <meta name="twitter:site" content="@username">  
    

    作用: 增强链接在社交媒体中的展示效果

  2. 主题色与 PWA 支持: 设置浏览器地址栏颜色或启动渐进式 Web 应用(PWA)功能:

    <meta name="theme-color" content="#ffffff"> <!-- 主题色 -->  
    <meta name="apple-mobile-web-app-capable" content="yes"> <!-- 全屏模式 -->  
    <meta name="apple-mobile-web-app-status-bar-style" content="black-translucent"> <!-- 状态栏样式 -->  
    

    作用: : 移动端 WebApp 开发

五. 其他实用属性

  1. 禁止自动识别格式: 阻止移动端自动将数字识别为电话号码

    <meta name="format-detection" content="telephone=no">  
    
  2. 安全策略: 设置内容安全策略(CSP)或禁止不安全内容混合加载

    <meta http-equiv="Content-Security-Policy" content="default-src 'self'">  
    <meta http-equiv="Content-Security-Policy" content="block-all-mixed-content">  
    

    作用: CSP 通常通过 HTTP 头部实现,但某些场景可用 meta 标签

六. 注意事项与最佳实践

  1. 优先级冲突: HTTP 头部设置会覆盖 meta 标签(如 Content-type)
  2. 性能优化: 静态资源长期缓存可通过文件名哈希(如 app.[hash].js)实现,而非依赖 max-age
  3. SEO 陷阱:避免滥用 keywords 或 重复堆砌,可能触发搜索引擎惩罚

总结: < meta> 标签时 html 中不可或缺的元数据工具,涵盖从基础编码到高级 SEO、移动适配等多场景。合理使用或可显著提升兼容性、用户体验和搜索引擎排名

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值