原型和原型链的理解
每个函数都有一个原型(prototype)
每个对象(prototype也是对象)都有__proto__,__proto__指向该函数的构造函数的prototype
当a(对象)访问a.name时,会先去找自身有没有name,没有就会通过__proto__找上层的prototype中有没有name,还是没有继续上向找,这个过程就是原型链
实例.__proto__ → 构造函数.prototype → Object.prototype → null
防抖和节流的理解、区别和实现
防抖是”第一次或最后一次说了算”
节流是”每隔一段时间执行一次”
宏任务和微任务
异步任务的两个类型:
常用的 promise 就是微任务
setTimeout 就是宏任务
requestAnimationFrame比较特殊,在微和宏之间
执行顺序: 同步代码 → 微任务队列清空 → 一个宏任务 → 微任务队列清空 → 下一个宏任务……
登录鉴权方案
JWT(JSON Web Token)
登录返回token,每次请求都带上,过期就用长期token刷新请求token
Session方案:
服务端存储会话,客户端只存sessionId,过期就401或重定向到登录。
requestAnimationFrame和setTimeout / setInterval
rAF用来制作动画,使用定时器会有不精确的时间间隔,过度消耗性能。导致掉帧,卡,浪费资源。
rAF主要用于(滚动监听、Canvas 绘图、DOM 动画、游戏循环),且是唯一的最佳选择
重放攻击
攻击者拿到完整的Curl,重复的请求发送,导致数据或服务出现问题。
常见手段:
- 时间有效期
- 一次随机数
- 时间 + 随机数 + 签名
- https(加密传输)
浏览器到页面生成完整过程
- DNS解析(本地缓存,再系统hosts,最后问DNS服务器)
- TCP三次握手,HTTPS还需要TLS握手
- 你好 → 你好我也好(HTTPS返回加密方式) → 开始
- HTTP请求
- 返回HTML并处理
- 浏览器解析HTML
- 构建DOM
- CSS到CSSDOM 加 <head> 防止阻塞
<SCRIPT>加 defer/asyn 防止阻塞
- DOM+CSSDOM 生成树
- 计算位置和尺寸
- 绘制到屏幕上
- 合成,图层以合并输出画面
闭包
一个函数能够记住并访问它自己和它周围的变量,即使它已经离开了出生地(return了),就是闭包。
闭包使函数拥有了“记忆力”。
常见场景:
- 防抖/节流
- 私有变量
- 函数工厂,根据参数返回不同的结果和做不同的事件
- 缓存/记忆函数,避免重复计算
闭包会让变量不被垃圾回收,用完要注意释放,避免内存泄漏。常见就是removeEventListener和clearInterval
onMounted(() => {
const timer = setInterval(() => {
console.log('running')
}, 1000)
// 组件销毁时没清除定时器 → 内存泄漏
// ✅ 应该在 onUnmounted 里清除
onUnmounted(() => clearInterval(timer))
})
function bindEvent() {
const bigData = new Array(100000).fill('数据')
function handleClick() {
console.log(bigData)
}
const btn = document.getElementById('btn')
btn.addEventListener('click', handleClick)
// 用完后移除监听器,闭包引用断开,bigData 可以被回收
return function cleanup() {
btn.removeEventListener('click', handleClick)
}
}
const cleanup = bindEvent()
// 不需要时调用
cleanup()
深拷贝和浅拷贝
浅拷贝:只复制对象的第一层
深拷贝:所有层级都复制,且是独立的新对象,互不影响
1. JSON.parse简单暴力
JSON.parse(JSON.stringify(obj))
2. structuredClone
const deep = structuredClone(obj)
3. 递归
function deepClone(obj) {
if notnull notobject
const clone = Array.isArray(obj) ? [] : {}
for(let key in obj) {
if(obj.hasOwnProperty(key)) {
clone[key] = deepClone(obj[key])
}
}
}
4. 生产项目用 lodash 库
Vue2 和 Vue3 的核心区别
- 响应式原理的区别,解决了无法检测属性新增/删除
- 使用区别:CompositionAPI和OptionAPI
- 组件支持多根节点
- 整体性能更好
Vue 响应式原理
vue2:Object.defineProerty vue3:Proxy 都根据其方法的get,set获取变更,从而展示出来,不同在于vue2需要遍历每个key才能监听,而且不知道新增和删除(使用Vue.set解决),数组更是需要重写方法才能监听(改写7个原生方法 push、pop、shift、unshift、splice、sort、reverse)
Vue3都是完美原生支持,就是不支持IE😃
computed 和 watch 的区别
一对多和多对一、缓存,有返回无返回,多次用computed,复杂用watch
v-model 的原理 ⭐️待复习
本质是语法糖,:value+@input,也就是prop+emit。有一个细节:在中文输入的时候不会触发监听(compositionstart开始合成文字和compositionend结束合成)
Vue3支持多个v-model:name,原理就是update:name
Vue 生命周期及父子组件执行顺序
Created -> mounted ->updated -> destroyed
到了Vue3就是steup -> onMounted -> onUpdated -> Unmount
keep-alive 是什么
组件缓存,避免不必要的,常用于tab切换,router-view
因为有缓存更新的需要使用用activated,缓存大小是可控的
Vue 组件通信方式
常用的prop + emit,ref + defineExpose(vue2不需要,默认导出全部)
跨组件provide / inject,其实用vuex/pinia更好
Vue Router 导航守卫
全局用beforeEach、afterEach,路由用beforeEnter,组件内onBeforeRouteEnter,onBeforeRouteUpdate,onBeforeRouteLeave
hash 模式和 history 模式的区别
hash带#,history不带,但是需要nginx配置,/ 指向index.html
nextTick 是什么
Vue更新DOM是异步的,我更新完成数据,如果要DOM的值,就会用nextTick
ref 和 reactive 的区别
ref基本类型和对象,reactive只能对象
ref需要带.value,reactive不需要
建议统一使用ref
defineProps 和 defineEmits 的用法
defineProps 接收定义的 props
defineEmits 定义可触发的事件
defineExpose 是什么
ref想用子组件方法,就需要defineExpose暴露方法在外面。
watchEffect 和 watch 的区别
一个不返回,一个返回旧值。
默认执行,默认不执行。
只能监听一个值,需要什么就写什么,这一点和computed类似,但是没有缓存,但是是支持异步的。
Teleport 是什么 ⭐️待复习
指定渲染位置,一般用于DOM全局的组件(提示,Loading,选框类)
Suspense 是什么 ⭐️待复习
Suspense做骨架图用的,加载慢的地方用。
v-show 和 v-if 的区别
v-if会销毁组件
v-show只操作DOM
为什么 v-if 和 v-for 不建议一起用
vue2中v-for等级高于v-if,先遍历再判断,就会有性能浪费。
vue3是反过来的,但是v-if拿不到v-for的变量会报错。
Vue 中 key 的原理
虚拟DOM的唯一标识,它是服务于 vue的diff算法,精准快速的找到这个DOM,并知道它是否更新。
什么是虚拟 DOM
真实DOM的一种抽象表达,每次数据变化,vue先生成新的虚拟DOM树,再通过diff算法对比新旧树,只有差异部分更新到真实DOM上,减少重绘。
DIFF算法
简单说就是用最省时,省力的方法,把虚拟DOM的变化同步到真实DOM上。
- 同层比较
- 利用key
- 四种命中策略,双端对比(头对头、尾对尾、头对尾、尾对头)
- 头对头/尾对尾 确认位置是否变化。
- 头对尾/尾对头 专门处理 翻转 的情况。
- 如果都没有中(Map 查找策略)
- 旧队列所有key存进map
- 拿新队形开头的key去map里面搜索
- 没有key,继续利复用。
vue3有一个更新 静态提升,就是启动不改变的HTML,如下
<div>
<h1>我是一个标题</h1> <!-- 静态节点:内容永远不变 -->
<p>8</p> <!-- 动态节点:内容会随 count 改变 -->
<span>固定文本</span> <!-- 静态节点 -->
</div>
作用域和作用域链
作用域是变量可被访问的范围
作用域链:函数在查找变量时时,一层一层(先块级函数级,找不到就全局)作用域往外找,一直找到自己的作用变量,这个查找链接就是作用域链。
Promise、async/await 和事件循环
Promise是解决回调地狱的一个方法。理论上可以无限链调用。
async/await是promise的语法糖,用同步代码的方式写异步代码
事件循环:JS是单线程,通过事件循环来处理异步任务,执行顺序
1. 执行同步代码
1. 先清空微任务队列promise
1. 再取宏任务setTimeout、setInterval
1. 继续重复2-3
其中有一个特殊:requestAnimationFrame,在微任务和宏任务中间触发,不属于事件循环,是浏览器的机制。
Vue3 相比 Vue2 的升级点
- compositionAPI
- 响应式
- 性能
- 多根节点
- 新组件:teleprot,SUspense
- 生命周期
- v-model可以多个
浏览器缓存机制 ⭐️待复习
浏览器缓存分两类
- 强缓存Cacthe-Control: max-age=3600,老写法是Expires-过期时间。
- 弱缓存(协商缓存)携带ETag/Last-Modified给服务器对比,没变化返回304,有变化200+新内容
CSS 垂直居中方法
- flex
- grid
- absolute + translate
- width + height + margin
- line-height
CSS 样式优先级
- !important
- 内联
- #ID
- 类选择,属性选择
- 标签
- 通配符*
如何防护 XSS 攻击 ⭐️待复习
- 不用innerHTML,document.write,eval(解析JOSN对象)
- CSP,后端通过HTTP 响应头限制页面能加载的资源来源
- HttpOnly Cookie,JS无法读取Cookie,请求自动带上。
- 富文本要用白名单或黑名单过滤
后台权限管理如何设计 ⭐️待复习
页面权限、按钮权限、接口权限
- 根据权限动态生成路由
- 根据角色控制按钮显示隐藏
- 每次请求携带 token
首屏加载优化方案 ⭐️待复习
- 效果好
- 路由懒加载&图片懒加载
- 组件按需引入
- 浏览器缓存
- tree-shaking(vue3)去除未使用代码
- 骨架图(让用户感觉很快)
- 小图转base64
- CDN GZIP 加速,服务器配置
- SSR
组件封装的理解和思路 ⭐️待复习
- 重复使用
- 功能相关独立
- 交互逻辑需要隔离
跨域是什么?如何解决
浏览器同源策略限制,协议、域名、端口相同,就会跨域。
- 开发环境 - vite/webpack 代理
- Nginx 反向代理
- 后端开放CORS
- JSON(现在基本不用了)
TypeScript 中 type 和 interface 的区别
type 用于基本类型 string boolean array number any
interface 联合类型,常用于接口设置或接收参数
var、let、const 的区别
var 声明前可以看,undefined 不报错,会全局污染。
let 声明前查看会报错。
const 和let一样,不能重新赋值,但是属性可以改。
== 和 === 的区别?
二等宽松
三等严格
区别:类型不同、null和undefined、0和false
this 的理解
| 调用方式 | this 指向 |
|---|---|
| 对象方法调用 | 调用该方法的对象 |
| 构造函数(new) | 新创建的实例 |
| call / apply / bind | 手动指定的对象 |
| 箭头函数 | 继承外层作用域的 this,不可更改 |
call / apply / bind 详解
三者都是用来手动指定 this 的,call 和 apply 都是立即执行,bin返回一个新函数
| call | apply | bind | |
|---|---|---|---|
| 是否立即执行 | ✅ 是 | ✅ 是 | ❌ 返回新函数 |
| 传参方式 | 逐个传 | 数组传 | 逐个传(可预设部分参数) |
内存泄漏的常见场景
- 定时器没有清除
- 事件监听没清除
- 闭包引用大对象
- 全局变量用多了
- DOM 引用没有释放
- watch没有停止
Webpack 和 Vite 的区别?
| Webpack | Vite | |
|---|---|---|
| 开发模式 | 打包后启动,项目越大越慢 | 基于 ESM 按需加载,启动极快 |
| 热更新 | 重新打包受影响模块,较慢 | 只更新变动文件,几乎即时 |
| 生产打包 | 自身打包 | 用 Rollup 打包 |
| 插件 | Loader | Plugin |
ox
Webpack 打包后再启动,Vite按需加载,启动很快。Webpack是自身打包,Vite用Rollup打包
Webpack 的构建流程
- 读配置文件,合并参数,创建compiler
- 确定入口,从 entry 开始
- 编译模块,各种loader
- 所有依赖关系理成,生成依赖图
- 输出,根据依赖图组成 Chunk,文件输出到 output
Git rebase 和 git merge 的区别
都是分支合并的作用。历史记录处理不同
mere 会生成新的历史,看的更清楚,真实记录(要合并到主分支用这个)
rebase 历史成为一条直线,会有漂亮整洁的commit,如果冲突多了,要一个一个的解决(个人分支用)
git reset 和 git revert
都是撤回提交
• reset 是”时光机”,直接回到过去,之后的历史消失
• revert 是”反向操作”,在历史上再加一笔”撤销”,原历史还在
已经push了,最好只用revert,除非你一个开发。
HTTP 状态码有哪些
- 2xx 成功
- 200 成功
201 post/创建成功204 delete常用
- 3xx 重定向
- 301 永久重定向
- 302 临时重定向
- 304 协商缓存,本地缓存
- 4xx 客户端error
- 400 参数
- 401 没有token
- 403 有token没权限
- 404 不存在
- 5xx 服务端error
- 500 内部错误
- 502 Nginx转发错了
- 503 服务挂了
GET 和 POST 的区别
GET默认有浏览器缓存,POS默认不缓存。
传参都可以有Body,URL参数,但是 RESTful API 设计规范
GET查询、POST新增、PUT修改、DELETE删除
说说 HTTP1.0 / 1.1 / 2.0 的区别
1.0 每次都建立新的TCP
1.1 持久连接,一个TCP连接可以多个请求,支持管道化,就是一个请求一个请求的来,会有阻塞问题
2.0 解决阻塞问题:一个 TCP 多个并行请求;1.x是文本协议,2.x是二进制;
3.0 用QUIC替换了TCP,解决了队头阻塞问题。目前就大厂和一些VPN用户在用。
WebSocket 是什么?和 HTTP 的区别?应用场景?
WebSocket 是一种全双工通信协议,连接后可以互相主动发消息,不需要轮询。
HTTP请求完就结束了。
WebSocket场景:实时聊天,客服,股票,监控,协同文档
说说回流(重排)和重绘的区别?如何优化?
回流:尺寸,位置,结构发生变化,开销大
重绘:外观变化、颜色、背景,不影响布局,开销比较小
回流一定触发重绘,重绘不一定触发回流。
优化手段:
- 合并修改width,height,margin或者加class
- 写一个虚拟DOM,写完再渲染
- CSS相关用transform替换left/top,使用will-change提升性能
CSS BFC 是什么?有什么作用?
BFC 块级格式化上下文,给元素加一个结界 作用:内外互不影响
以下可以触发BFC
overflow不为visibledisplay: flex / grid / inline-blockposition: absolute / fixedfloat不为none
说说 flex 布局的常用属性
flex-direction 方向
justify-content X轴
align-items Y轴
flex-wrap 换行
gap 间距
子元素: flex:1 等分剩余空间
order:1 排序
说说 CSS Grid 布局
二维布局,可以同时控制行和列,合适整体页面框架,表格布局
grid-template-columns 控制列
grid-template-rows 控制行
grid-template-areas 命名区域
说说 CSS 预处理器(Sass/Less)的理解
CSS预处理是对CSS扩展,增加了变量、嵌套、混入、函数一些功能,最终编译成CSS
现在趋势:Vue3也推荐用Sass,原生CSS的变量可以替代部分Sass的功能
说说响应式设计的原理和实现方式
响应式就是不同尺寸都有良好的效果
方式:
- 媒体查询
- 弹性单位 %,vw/vh,em
- 弹性布局 flex,grid
字体方案:
- vw方案(根据设计稿计算),使用postcss-px-to-viewport自动计算
- clamp 设置最小值和最大值
说说事件委托(事件代理)是什么?应用场景?
事件委托:利用事件冒泡,把子元素的事件监听器绑定到父元素上,由父元素统一处理。
// ❌ 每个 li 都绑定一个监听器
document.querySelectorAll('li').forEach(li => {
li.addEventListener('click', handleClick)
})
// ✅ 委托给父元素,一个监听器搞定
document.querySelector('ul').addEventListener('click', (e) => {
if (e.target.tagName === 'LI') {
handleClick(e.target)
}
})
说说 JavaScript 继承的几种方式
- 原型链继承
- 构造函数继承
- 组合继承
- ES6 Class继承(现代写法)
你是如何实现与蓝牙设备(BLE)通信的? (项目相关)
使用navigator.bluetooth
- 搜索,筛选 requestDevice
- 连接 connect
- 获取服务 用服务ID 拿到service
- 获取特征值 特征ID 拿到characteristic
- 使用characteristic,读取数据 / 监听通知 / 写入数
- 读取的时候会设计密码算法(各种公司各种设备都不同)
// 1. 请求设备(弹出选择框)
const device = await navigator.bluetooth.requestDevice({
filters: [{ name: '变频器设备名' }],
optionalServices: ['battery_service', 'your-service-uuid']
})
// 2. 连接 GATT 服务
const server = await device.gatt.connect()
// 3. 获取主服务
const service = await server.getPrimaryService('your-service-uuid')
// 4. 获取特征值(Characteristic)
const characteristic = await service.getCharacteristic('your-char-uuid')
// 5. 读取数据
const value = await characteristic.readValue() // 返回 DataView
// 6. 监听通知(设备主动上报)
await characteristic.startNotifications()
characteristic.addEventListener('characteristicvaluechanged', (e) => {
const data = e.target.value // DataView
const byte = data.getUint8(0) // 读第一个字节
})
// 7. 写入数据(发指令给设备)
const command = new Uint8Array([0x01, 0x02, 0x03])
await characteristic.writeValue(command)
前端处理 16 进制数据时,ArrayBuffer 和 DataView 怎么用?
ArrayBuffer 是原始二进制数据的容器,不能直接读写,需要通过视图来操作。
DataView 是其中一种视图,可以精确控制读取的字节位置和数据类型。
蓝牙返回的数据是 DataView
蓝牙连接不稳定、丢包或数据延迟,前端做了哪些重试或兜底机制?
- 监测断开,提示用户,自动重连
- 丢包,超时,一般在300ms以内,过了时间就算超市,等待100ms左右,继续尝试,尝试2次,失败了标记,告诉用户检查设备指示灯或重新连接
硬件状态频繁上报时,前端如何保证渲染不卡顿?
- 节流控制更新频率
- requestAnimationFrame 批量更新
- 图表类数据用虚拟列表
动态表单引擎是如何设计的?
借鉴Vben Admin的Schema 结构设计,JSON 驱动表单,天然支持动态渲染和联动。
fields > key,name,label,required,reles,show,showWhen
大数据量列表渲染如何优化?虚拟列表原理是什么?
虚拟列表滚动
原理:只渲染可视区域内的条目,滚动时动态替换内容,DOM 节点数量始终保持很少。
列表监听scroll,动态更新 startIndex
可视区高度:500px
每条高度:50px
可视区最多显示:10条
那只渲染14条左右的数据
不定高的虚拟列表更为复杂,实际项目还是直接使用成熟的三方库 vxe-table、vue-virtual-scroller、Element Plus
JSBridge 原理是什么?H5 如何调用 iOS 原生能力?
- URL Scheme 假URL请求,原生拦截
- 封闭 window.webkit 方法
window.webkit.messageHandlers.scan.postMessage
iOS/Android 不同机型兼容性问题怎么排查和解决?
-
刘海屏/安全区(部分app需要背景全屏),使用
safe-area-inset -
键盘弹起输入框被遮挡
- 监听focusin调整页面或者滚动页面
-
IOS滚动/穿透,给body加上fixed overflow
body { overflow: hidden; position: fixed; width: 100%; } -
Android 字体渲染不一致
* { -webkit-font-smoothing: antialiased; } -
调试用chrome的chrome://inspect调试webview,IOS需要手动打包真机调试
Vue2 升级 Vue3 技术选型的思路?
先根据项目判断是否值得升级,长期/短期项目;
项目风险评估:检查依赖;
团队成本:Vue3学习成本,历史代理的改造量;
迁移思路: 先用兼容模式,将vue2在vue3的vite在跑起来。
逐步把Optino API改Composition API。
新功能必须用 Vue3,如果碰到依赖的vue2一并改造。
Vue2 和 Vue3 在 computed 和 watch 执行顺序
执行顺序上基本一致,响应式数据变化时先触发watch,再触发computed
为什么 JS 用单线程?Event Loop 存在的意义?
刚出生时是因为网面交互,为了避免并发问题,同一时刻既想删除DOM又想修改样式,如果多线程就冲突了。所以JS就一直采用单线程。
单线程就意味着时间长,所以就把网络请求,文件读写,定时器给浏览器(多线程环境)去处理。
任务队列 + Event Loop 的工作方式:
1. 主线程执行同步代码
2. 异步任务完成后,callback 进入任务队列
3. Event Loop 不断检查:主线程空了吗?空了就从队列里取任务执行
4. 回到步骤 1
Event Loop 就是两者协调的枢纽
为什么使用 JSVerbalExpressions?它解决了原生正则的什么痛点?
作用是匹配基因序列校验。
链式调用,可读性好 ,可维护性高。 缺点就是性能略差原生正规。
前端高亮分析长篇基因序列数据,怎么做性能优化?
- 虚拟滚动
- 分段懒加载
- CSS优先 content-visibility: auto 不渲染看不到的地方
- Canvas 渲染
按钮级权限如何实现?
- vue的自定义指令,diretive中拿store做判断
- 封闭组件,原理是一样的,引入组件,传入权限别名(user.create)
路由级权限如何实现?动态路由 addRoutes
-
前端存储完整路由,用户登录后根据权限过滤出有权限的路由
-
用户权限发生变动,使用addRouter添加路由权限
TypScript 泛型在封装通用组件(如动态 Table)时如何使用?
泛型是为了使用组件和创建组件的时候用的数据类型是正确的。使用keyof T组件更安全。使用组件更方便,在ide中可以直接.出来
日常开发中如何利用 AI 辅助编程?有哪些排错或提效场景?
- 主要场景,代码生成,写组件。
- 老代码或遗留项目,功能和代码解读。
- 文档查询,比查文档快。
主要是辅助,核心逻辑和业务代码还是需要自己写。
要保证质量就要,Ai Review + 人工审核 + 单元测试
AI擅长重复性工作,但业务理解、系统设计、创造性问题还是人的强项
Cordova 到纯原生再到 Vue3,谈谈不同跨端技术的选型场景
-
Crodova
Webview 开发效率高,只需要安卓和Ios出一个壳子(Ai写就可以),一套代码跑全平台
性能有瓶颈,复杂动画卡顿,全WebView的iOS可能会有审核问题。
适合业务简单,交互动画不需要很酷炫或高级,内部工作,快速开发迭代
-
纯原生
性能强,体验好
多平台成本高
高性能App,复杂交互,游戏
-
React Native / Flutter
JS能直接控制原生,一套代码双端,接近原生
某底层能力受限,生态不如原生(国内)
-
uniapp/vue3
一键导出各种小程序
不适合做App,只适合简单业务的小程序
RN受限地方:
1. 复杂的手势,拖拽没问题,多指,连笔性能不如原生 2. iOS后台问题,后台播放媒体经常失效。 3. 3D图形,RN 使用 WebGL 性能一般,这方面 Flutter 的 Skia 引擎强一些。WebGL和 Flutter 的 Skia
WebGL 是”在浏览器里用 GPU 画一切”,Skia 是 Flutter 的”画板”,负责把 Dart 代码变成平台的像素。
面对紧急需求或技术难点(如第一次接触蓝牙通信),如何快速攻克?
- 拆解问题,问AI做计划。
- 不懂ble协议,先查文档,了解流程
- 先跑Demo
- 能跑能运行就行
- 能搜索到蓝牙
- 功能玄序渐进的加
- 功能一个一个测,测完再下一个
- 遇到问题要设置止损时间点
- 到点就换方案/救助,不能死磕
Vue 中自定义指令的应用场景有哪些?
- 常见权限控制
- 自动聚焦
- 图片懒加载
- 复制到剪贴板
React 核心关键词速记
- JSX → UI语法(JS写HTML)
- Component → 函数组件
- Props → 组件传参
-
State → 组件状态
- useState → 状态管理
- useEffect → 副作用处理
- useLayoutEffect → 同步副作用(阻塞渲染)
- useMemo → 缓存值
- useCallback → 缓存函数
- useRef → 持久引用(不触发render)
- useContext → 跨组件传值
-
useReducer → 复杂状态管理
- React.memo → 组件缓存(props不变不渲染)
- useMemo → 避免重复计算
- useCallback → 避免函数重复创建
-
key → diff优化标识
- render → 计算UI(纯函数)
- commit → 更新DOM
- diff → 找变化
-
Fiber → 调度机制(可中断)
- 单向数据流 → 父 → 子
- props → 传数据
-
callback → 子传父
- react-router → 路由管理
- BrowserRouter → 路由容器
- Route → 路由配置
- useNavigate → 跳转
-
useParams → 取参数
- useEffect → 请求/订阅
- cleanup → 清理副作用
- debounce → 防抖
-
throttle → 节流
- 组件拆分 → 提高复用
- 自定义Hook → 逻辑复用
-
受控组件 → 表单状态受控
- useState → 局部状态
- useContext → 跨层级
- useReducer → 复杂逻辑
- Redux → 全局状态
-
Zustand → 轻量状态库
- Suspense → 异步加载占位
- lazy → 组件懒加载
- StrictMode → 开发检测
- SSR → 服务端渲染
- hydration → 客户端接管
小程序速记
-
Page 定义页面逻辑 Page({})
-
Component 定义组件 Component({})
-
App 全局入口 App({})
-
插值 数据绑定
- wx:if 条件渲染(会销毁节点)
- hidden 控制显示隐藏(不会销毁)
- wx:for 列表渲染
-
wx:key 列表唯一标识(优化渲染)
-
block 不生成节点的容器
-
bindtap 绑定事件(会冒泡)
-
catchtap 阻止冒泡
-
dataset 传递自定义数据
-
e.currentTarget.dataset 获取数据
-
data 页面数据 data: { count: 0 }
-
setData 更新视图(核心API) this.setData({ count: 1 })
-
路径更新 局部更新优化 this.setData({ ‘list[0].name’: ‘xx’ })
-
onLoad 页面加载(只执行一次)
-
onShow 页面显示(每次触发)
-
onReady 首次渲染完成
-
onHide 页面隐藏
-
onUnload 页面销毁
-
wx.navigateTo 保留当前页面跳转
-
wx.redirectTo 关闭当前页面跳转
-
wx.switchTab 跳转 tab 页面
-
wx.reLaunch 重置页面栈
-
页面栈(10层) 最大 10 层
-
properties 父 → 子传值
-
triggerEvent 子 → 父通信
-
slot 内容分发(提高复用)
-
wx.request 发起请求
-
Promise封装 提高可维护性
-
减少 setData 避免频繁调用
-
合并 setData 批量更新
-
避免大数据传输 减少通信成本
-
分包加载 提升启动速度
-
wx:if vs hidden 合理选择
-
view 类似 div
-
text 文本
-
image 图片
-
button 按钮
-
input 输入框
-
双线程模型 逻辑层 + 渲染层
-
无 DOM 不能直接操作节点
-
数据驱动视图 通过 setData 更新 UI
-
必背“短句”
👉 双线程 小程序采用逻辑层和渲染层分离。
👉 setData 用于更新视图,但频繁调用会影响性能。
👉 生命周期 onLoad 只执行一次,onShow 每次进入都会触发。
👉 路由 navigateTo 保留页面,redirectTo 替换页面。
👉 组件通信 父传子用 properties,子传父用 triggerEvent。
👉 事件 bindtap 会冒泡,catchtap 阻止冒泡。
👉 setData 原理 & 性能优化
必答:
- 数据从逻辑层 → 渲染层
- JSON 序列化传输
👉 优化:
- 批量更新
- 避免大对象
- 局部更新路径写法
项目: 我做了一个行李寄存预约小程序,用户可以填写取货地、还货地、取件时间、归还时间、联系人和类型来创建预约。项目里我把订单列表抽到了 MobX store 中做统一管理,用于跨页面共享订单数据;创建页主要维护表单本地状态,提交后调用 store action 创建订单;列表页通过 mobx-miniprogram-bindings 直接绑定 store,实现订单数据变化后的自动更新;详情页则展示订单状态,并模拟待审核、接单、寄存中、已退款、完成等状态流转。
**🧠 小程序本质 **
小程序是运行在微信环境中的轻量级应用,采用双线程架构,通过 setData 实现数据驱动视图。
**🧠 生命周期 **
onLoad 只执行一次,onShow 每次进入都会执行。
**🧠 路由 **
navigateTo 保留页面,redirectTo 替换页面,最多 10 层。
**🧠 性能 **
减少 setData,避免大数据传输。
**🧠 登录 **
wx.login 获取 code,后端换 openid 并返回 token。
🧠 支付
后端生成支付参数,前端调用 requestPayment。