前端面试题

1,Promise构造函数是用来处理异步任务回调函数的一种方案,可代替callback函数

异步任务不会进入主线程而是由浏览器线程执行,执行完毕后会调用主线程的回调函数,promise就是用来处理这个回调函数

async(异步)关键词作用于函数体(主线程同步执行),用来标识函数内部有异步任务,await关键词用于async异步函数内部,用来阻塞线程等异步任务执行完毕再往下执行,await后的代码会打包成微任务,等回调函数返回后,进入主线程处理

状态:等待,成功,失败

2,构造函数

构造函数会自动创建一个空对象

工厂模式的情况下,构造函数相比普通函数可节省内存,普通函数多次调用就会创造一个新的方法副本

3,数组扁平化flat函数

arr.flat()

参数可以数字,或者不传(默认1),或者Infinity扁平化全部层级

4,异步组件:defineAsyncComponent

父组件加载会返回一个占位符,组件加载完成后替换占位符

优:加快初始化时间,按需加载,避免资源浪费

缺:动态导入会发起http请求,不利于浏览器爬取和索引

5,函数声明和函数表达式

函数声明会导致变量提升致作用域顶部,函数表达式是变量定义,重复定义会覆盖同名函数声明和函数表达式

6,vue2和vue3

响应式系统升级、写法更灵活,采用组合式api、diff算法优化Dom渲染性能提升,引入Tree Shaking打包体积更小、ts支持性更好

diff:在vue3数据改变后虚拟Dom生成真实Dom的过程中,对比新旧Vnode节点得出修改的最小单位

7,spa单页应用怎么加快加载速度

1,代码组件化,使用异步加载

2,资源预加载,懒加载,缓存重复使用的资源

3,静态资源使用CDN

4,不要重复请求api

5,循环dom使用有效的key值

6,较大的库使用外部扩展,如lodash

7,页面路由跳转有些页面能缓存就缓存

8,首次加载服务器端渲染快于客户端渲染

9,用户体验上用骨架屏之类的

8,组件传值

1,props和emit

2,provide和inject

3,状态管理(小型项目使用localstrorage或者全局变量)

4,事件总栈eventbus

5,uni.on和uni.emit

6,父传子,ref获取子组件的实例

7,作用域插槽

9生命周期函数

10,盒模型

每个元素都是一个矩形盒子,有外边距,内边距,边框,内容

标准盒模型:日常使用的,高宽为内容

怪异盒模型:高宽为内边距加边框加内容

• box-sizing: content-box; (默认值) - 使用标准盒模型。

• box-sizing: border-box; - 使用怪异盒模型。

11,响应式设计

一套代码适应不同分辨率

使用百分比,媒体查询,使用flex或者grid布局,unocss响应式前缀(sm:p-3,md:p-3)

媒体查询:

/* 超小设备 (手机, 小于 768px) /
/
通常不需要 min-width 查询,因为这是默认的移动样式(Mobile First) */

/* 小型设备 (平板, 768px 及以上) */

@media (min-width: 768px) { ... }

/* 中型设备 (笔记本/小桌面, 992px 及以上) */

@media (min-width: 992px) { ... }

/* 大型设备 (大桌面, 1200px 及以上) */

@media (min-width: 1200px) { ... }

/* 也可以使用 max-width /
@media (max-width: 767px) { ... } /
仅对手机生效 */

12,CSS modules

样式合理,实现局部样式,类似vue的scoped

Css modules在编译时转换类名

Scoped在运行时修改类型,类名后添加属性标识

13,js原型链

每个对象都有原型链,如果访问这个对象的一个属性或者方法,这个对象本身没有就会去原型链上原型中逐个往上查找,直到找到或者原型链顶端Object.prototype,比如定义一个数组,使用data.toString(),因为原型链顶端有这个方法,所以可以执行成功

Es6的class 语法糖可以继承原型链

Class son extends father{}

14,js的事件循环Event Loop(无限循环,不会停止)

监听和调度任务,处理高并发的异步任务,保证单线程不会堵塞

先同步任务,微任务(promise回调函数,比如await接口返回后复赋值),再宏任务(settimeout),最后再检查有没有微任务需要执行

(微任务执行完毕,再执行一个宏任务,继续检查有没有微任务,全部任务完成后会进入休眠继续等待下一个进入的任务)

微任务:加急任务

宏任务:普通任务

15,在ts中生成dom

1,h函数生成虚拟节点VNode,render函数把虚拟节点生成真实dom

2,tsx < script setup lang="tsx">

16,vue-router

两种模式

hash:url中带#,通过hashchange实现路由切换,兼容性好

history:url正常模式,比较美观,通过pushstate和replacestate实现,需要服务器端支持,避免刷新出现404,利于seo优化(浏览器搜索引擎不解析url的#后内容)

17,导航守卫

路由跳转执行的钩子函数

router.beforeEach路由跳转前的前置守卫,用于验证登录,权限,页面是否存在等

router.afterEach路由跳转后的后置守卫

18,状态管理:管理全局共享数据和相应操作数据的方法

Pinia更轻量级,支持ts,写法使用组合式,默认支持模块化

19, vite打包体积过大

1,使用tree shaking

2,按需引入

3,开发环境需要的插件安装在开发配置中,不需要安装到生产配置

4,图片等静态资源使用cdn

5,配置高效的压缩算法

6,配置代码分割策略

20,Websocket

建立在http请求上的一个特殊请求

步骤:

1,建立连接

1.1,客户端握手

客户端发起一个new Websocket(url)请求,请求头带两个信息,标识是Websocket请求。

Upgrade: websocket // 将协议升级为Websocket

Connection: Upgrade // 此次连接需要转换协议

Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ== // 随机Base64 密钥,由浏览器生成

Sec-WebSocket-Version: 13 // 使用的 WebSocket 协议版本(13是现行标准)

1.2,服务器响应

服务器支持websocket则返回101响应,并同样返回这两个标识

Upgrade: websocket // 同意升级为Websocket

Connection: Upgrade // 确认转换协议

2,数据传输

握手成功后TCP保持打开,通过数据帧进行通信

数据帧头特别小,这是他能保证实时通信不延迟的原因

3,心跳机制

心跳机制用来检查websocket是否正常连接,服务器端向客户端发请求

前端实现

1,创建连接

// 使用 'ws://' 用于非加密连接(开发环境)

// 使用 'wss://' 用于加密连接(生产环境,等同于 HTTPS)

const socket = new WebSocket('wss://your-websocket-server.com/chat');

2,使用websocket方法获取服务器端数据或者向服务器端传递数据

3,完毕后在onUnmounted 中使用close方法清理连接

21,watch

监听多个属性

watch(

() =\> state.user.name, () =\> state.user.age\], (\[newName, newAge\], \[oldName, oldAge\]) =\> { console.log('name 或 age 变化了'); } ); 22,普通函数与箭头函数的区别 写法不一样,this指向不同,普通函数可作为构造函数,箭头函数不行 普通函数不return会返回undefined 22,typeof返回 类型 返回值 Undefined "undefined" Null "object" (历史遗留问题) Boolean "boolean" Number "number" BigInt "bigint" String "string" Symbol "symbol" Function "function" 其他对象 "object" 23,组件透传 24,实现v-model 一,使用update:modelValue \ 二,使用defineModel(vue3.3+) const modelValue = defineModel() // 带类型和默认值 const modelValue = defineModel('默认值') // 多个 v-model const firstName = defineModel('firstName', { default: '' }) const age = defineModel('age', { default: 0 }) 25,es6 26,nextTick 响应式数据更新后,会生成一个异步的微任务加入到队列,等待事件循环调度主线程执行这个微任务,nextTick就是一个特殊的promise异步任务,在等待数据更新的微任务执行完毕后再执行,所以他能保证获取到最新的Dom 27,闭包 闭包就是能够读取其他函数内部变量的函数,或者说是一个函数和其周围状态 原理: 函数在执行时,会创建一个作用域链。通过作用域链,内部函数可以访问外部函数的变量,即使外部函数已经执行完毕,只要内部函数还在被引用,外部函数的变量就不会被垃圾回收,从而被"封闭"在内部函数中。 28,作用域链 作用域:作用域就是变量和函数的可访问范围 作用域链:当在某个作用域内访问一个变量或函数时,JavaScript 引擎会遵循一个从当前作用域到外层作用域逐级查找的机制。这个查找路径就像一条链子,所以我们称之为作用域链。 29,深拷贝浅拷贝 "浅拷贝时,嵌套对象的内存地址指向同一个;深拷贝时,所有层次的内存地址都是不同的。" 浅拷贝,展开运算符{...obj},object.assign 浅拷贝只有嵌套对象的会指向同一个内存地址 深拷贝,cloneDeep 30,使用unocss实现媒体查询响应式样式 使用响应式前缀 31,组件开发 • 单一职责 - 每个组件只关注一个特定功能 • 可复用性 - 通过props和插槽提供灵活性 • 可维护性 - 清晰的接口和良好的文档 • 性能优化 - 合理使用响应式数据和生命周期 32,怎么实现一个vue3的路由 创建一个路由文件,实现路由配置,创建路由,然后挂载到main.ts中,页面使用router-link渲染路由链接,使用router- view显示路由页面 动态路由: 1,定义基础的路由文件,404,登录页等 2,从后端获取路由数据(main.ts或者apo.vue中预加载,路由守卫中按需加载) 3,转换路由格式{path,component,name,meta} 4,添加动态路由:router.addRoute(route) 5,路由守卫控制权限:router.beforeEach 6,渲染菜单:路由链接:router-link 路由视图:router-view 也可以使用component 标签实现,不需要3,4,6步 设置路由缓存: \ 插入的内容 \