简介:面向微信小程序与前端岗位求职者的一份高频面试题速查手册,以PDF形式整理了二十道常见问题。内容覆盖必备文件与全局配置、事件传值、数据请求封装、页面间传参、路由跳转等核心模块,并将小程序与Vue.js在数据绑定、事件绑定、双向绑定上的差异,以及WXML与HTML、WXSS与CSS的异同做了对照归纳,还梳理了onLoad、onShow等生命周期函数与wx.navigateTo、wx.redirectTo等路由方式。整个资源包只有1个PDF文件,大小182KB,篇幅紧凑,适合离线阅读或面试前集中翻阅。文件以问答形式逐题给出结论、关键写法和易错点,例如data-*传值不能包含大写字母、WXSS仅支持部分选择器等,能帮助开发者快速搭建小程序知识框架、查漏补缺。目前已有747人学习下载,对准备前端或小程序面试的读者有较好的参考价值。
1. 小程序常见面试题,到底在考什么?
一份《小程序常见面试题20题》放在你面前,从目录看每题都有标准答案,可真到了面试现场,面试官只挑其中一道往深了问,问到你接不住话。小程序面试题不是网页开发题的简单换皮,它考的是在双线程架构、分包限制、组件化约束下,你怎么设计数据流、怎么理解生命周期、怎么做性能取舍。这篇文章不打算逐题给答案,而是把 20 题背后的考点拆成一条知识链路:架构、生命周期、通信机制、答题框架、避坑经验,最后给你一套能迁移到任何前端方向的面试准备方法。适合已经写过小程序但答题不成体系的前端开发者,也适合准备转小程序方向、想快速建立完整知识框架的同学。
我按"原理 → 操作 → 避坑 → 自查"的顺序展开,每章给的代码都能在开发者工具里直接跑,给的答题结构都能在面试现场直接套。读完你会发现,面试官手里的 20 道题,其实是在用不同问法反复确认同一条知识链是否完整。
2. 小程序架构与生命周期:第一道题就把候选人分成两档
面试开始五分钟内,面试官通常会抛出一道"请说说小程序的运行架构"。这道题看似基础,实际上能把候选人分成两档:一档只能说"小程序是双线程的",另一档能解释清楚为什么必须双线程、冷启动和热启动有什么区别、生命周期谁先谁后。如果你还能把页面栈、组件生命周期、数据通信串成一条清晰的链路,面试官对你的判断会直接升一档。这一章先把这条链路完整走一遍,最后用一个日志 Demo 让你亲手验证触发顺序,避免背了答案却说不清原理。
2.1 双线程模型:为什么渲染层和逻辑层必须分开
小程序运行环境不是普通浏览器页面,而是由逻辑层(App Service)和渲染层(多个 WebView)组成。逻辑层负责业务逻辑、数据处理、接口请求和状态管理;渲染层负责把 WXML 模板和 WXSS 样式渲染成用户看到的界面。两层之间没有直接共享数据的通道,所有数据交换都要经过一层"数据序列化——跨线程传递——渲染层解析执行"的通道。也就是说,你每次调用 setData,都不只是改一个对象,而是在做一次跨线程通信。
面试追问"为什么必须分开"时,建议从三个角度回答。第一是安全隔离:逻辑层拿不到渲染层的 DOM,渲染层也碰不到逻辑层的完整运行时,权限边界清晰,恶意脚本能做的事被限制在一个可控范围内。第二是稳定性与性能:渲染层是 WebView,某个页面渲染崩溃不至于把整个逻辑层一起拖垮;逻辑层跑在独立引擎里,不受单页面复杂 DOM 操作的干扰。第三是跨端一致性:小程序要跑在多种平台容器里,渲染层在不同端可能是不同的 WebView 实现,而逻辑层由框架统一接管,业务代码可以保持尽量一致。能答出这三层,这道送分题才会变成你的加分题。
2.2 生命周期触发顺序:页面与组件谁先谁后
小程序生命周期是面试必考,而且专门喜欢交叉着问。页面生命周期五个:onLoad、onShow、onReady、onHide、onUnload。组件生命周期五个:created、attached、ready、moved、detached。单独背这两个列表并不难,难点在于交错时的先后顺序。我把总结的顺序表放在下面,建议直接记进笔记。
| 场景 | 触发顺序 |
|---|---|
| 冷启动小程序 | App onLaunch → App onShow → Page onLoad → Page onShow → Page onReady |
| 组件首次挂载 | 组件 created → 组件 attached → 组件 ready → 页面 onReady(组件 ready 在页面 onReady 之前) |
| 页面 A 跳页面 B | A onHide → B onLoad → B onShow → B onReady → A 保持在 onHide 状态 |
| 从 B 返回 A | A onShow → B onUnload |
| 切后台再回前台 | App onHide → Page onHide → 回到前台后 App onShow → Page onShow |
页面栈深层逻辑同样要懂:每调一次 wx.navigateTo 就压入一个新页面,栈深度上限是十层,超过十层 navigateTo 会失败。我一般会封装一个跳转工具,用 getCurrentPages().length 判断栈深度,接近上限时改走 wx.redirectTo 或 wx.reLaunch,避免用户在页面链里无限往下钻。面试时能主动提这个封装思路,说明你不只是背了限制,而是真的被十层栈坑过。
2.3 冷启动、热启动、页面栈:三个容易被含糊带过的考点
冷启动指用户首次打开小程序,或小程序进程已被系统回收后再次打开,此时需要重新创建逻辑层与渲染层、重新加载代码包,所以耗时明显更长。热启动指小程序已经在后台存活,用户重新进入,此时不需要重新加载代码包,只触发 App 的 onShow 和页面的 onShow。这个区别直接关联到一个高频优化问题:为什么小程序启动这么慢?
冷启动慢的根因通常集中在三块:主包体积过大、启动阶段同步逻辑过多、首屏依赖的接口过慢。常见方案是把非首屏页面拆到分包,让首屏只加载主包资源;同时避免在 onLaunch 里做大量同步读写,尤其不要一启动就把大对象从 storage 拉到内存。热启动慢的场景一般不是加载慢,而是数据陈旧——用户在后台挂了一小时再回来,列表页展示的还是旧缓存,这时在 onShow 里做增量刷新才是正确姿势。回答里如果能区分"冷启动要减资源、热启动要管时效",面试官就会确认你是有实战体感的。
2.4 打开开发者工具验证:最小生命周期日志 Demo
理论讲再多,都不如把日志打出来看一遍。我建议在开发者工具里新建一个测试页面,把 App 和 Page 的生命周期回调全部加上 console.log,然后分别执行四个操作:冷启动、切后台、回前台、关闭页面。你看到的输出顺序,会帮你彻底搞清楚哪些回调重复触发,哪些只在创建时触发一次。
// app.js App({ onLaunch() { console.log('[app] onLaunch'); }, onShow() { console.log('[app] onShow'); }, onHide() { console.log('[app] onHide'); } });// pages/trace/trace.js Page({ onLoad(options) { console.log('[page] onLoad', options); }, onShow() { console.log('[page] onShow'); }, onReady() { console.log('[page] onReady'); }, onHide() { console.log('[page] onHide'); }, onUnload() { console.log('[page] onUnload'); } });逻辑说明:App 生命周期随小程序整体的启动与前后台切换触发,Page 生命周期随页面实例的创建、显示、隐藏、销毁触发。两者交错后,固定的规律是"先 App 后 Page"。参数说明:onLoad 的 options 是页面跳转时拼接在 url 上的 query 参数,首次创建必传;冷启动时还能从 options 里读到场景值,用来区分用户是从哪里进入小程序的。
跑完 Demo 你会发现,页面从后台回前台只触发 onShow,不会重新触发 onLoad 和 onReady。这个观察很值钱——很多列表页刷新逻辑写在 onLoad 里,从详情页返回时数据永远是旧的。以后面试被问"为什么我的页面数据不刷新",根因就在这里。
3. 小程序数据与通信机制:面试里最容易被追问的区域
20 道题里,直接考 setData 的至少五道,变着法追问:setData 是同步还是异步?为什么 this.data 已经新了视图却还旧?频繁 setData 会有什么后果?另一类高频题考页面间通信:navigateTo 之后怎么回传数据,tabBar 页面怎么感知变化,组件和页面之间怎么传事件。这一章把通信机制拆成三个层次:数据到视图、页面到页面、组件到页面,每层都给出可运行代码和参数说明。
3.1 setData 的双轨更新:为什么 this.data 同步而视图异步
先说结论:调用 setData 后 this.data 立即更新,视图渲染异步完成。这个"双轨更新"让很多人翻车,因为面试官会追问:"this.data 都同步了,你怎么还说 setData 是异步的?"你要分清两件事:逻辑层本地数据确实是同步替换的,但从逻辑层到渲染层的传输、解析、绘制,全程异步。所以严格说,setData 是"数据同步、渲染异步"。
另一个高频追问点是 setData 的性能损耗。每次调用都要做一次跨线程序列化传输,传的数据越大、频率越高,损耗越明显。面试时讲优化方向就三个:减少调用次数、缩小更新范围、降低触发频率。缩小范围有个很实用的技巧,就是路径更新:this.setData({ 'list[0].name': 'newName' }),只更新数组里某一项,而不是把整个 list 重新传过去。滚动场景则是节流的经典应用场景。
// 反例:滚动回调里高频 setData,一帧一次,数据量还在涨 onPageScroll(e) { this.setData({ scrollTop: e.scrollTop }); }// 正例:节流合并更新,一百毫秒最多一次,只传最后的值 onPageScroll(e) { this._latestScrollTop = e.scrollTop; if (this._throttled) return; this._throttled = true; setTimeout(() => { this.setData({ scrollTop: this._latestScrollTop }); this._throttled = false; }, 100); }逻辑说明:节流的核心是先用实例变量存最新滚动位置,再按固定间隔把位置写入 setData,这样渲染线程收到的更新频率被压住,首屏和滚动都不容易卡顿。参数说明:setData 的第二个参数是渲染完成回调,适合放依赖新视图的代码,比如查询节点高度;第一个参数支持路径 key,这是官方支持的字段级更新方式,性能优于传整个对象。
3.2 页面通信三选一:EventChannel、globalData、storage 的边界
页面间怎么传数据,会以各种形式出现:B 页面怎么把结果回传给 A?tabBar 页面之间怎么共享登录状态?跨页面分发通知用什么?核心都是让你做方案选型。三个候选没有绝对好坏,只有边界是否合适。我这里给出我的判断标准。
第一种 EventChannel,适合页面跳转场景下的即时双向通信。在 wx.navigateTo 的 success 回调里,通过 res.eventChannel.emit 给目标页面发消息;目标页面在 onLoad 里用 this.getOpenerEventChannel().on 接收。这套机制比在 url 上拼参数灵活,也不会污染全局状态。要注意它是页面实例级管道,页面卸载后管道销毁,不能当全局事件总线用。
// 页面 A 跳转,并向 B 发初始数据 wx.navigateTo({ url: '/pages/detail/detail?id=1', success(res) { res.eventChannel.emit('initData', { from: 'A', id: 1 }); } });// 页面 B 接收消息,并回传结果 Page({ onLoad() { const channel = this.getOpenerEventChannel(); channel.on('initData', (data) => { console.log('B 收到', data); channel.emit('result', { ok: true, value: 42 }); }); } });逻辑说明:emit 是单向发送,on 是注册监听。B 页面在 onLoad 拿到 channel 后,可以通过同一个 channel 再 emit 回 A。参数说明:A 页面接收回传结果的时机要注意——如果 A 在跳转成功回调里注册监听,此时页面栈顶层还是 B,A 的实例没有进入 onShow,建议在 A 的 onShow 里注册监听,确保返回时能收到消息。
第二种 globalData,适合低频变更、读取频繁、不需要持久化的全局数据,比如用户信息、配置项。但 globalData 不是响应式的,修改后不会通知页面刷新,页面要想感知变化只能在 onShow 里重新读取,或者自己写一套简单的订阅通知。第三种 storage,适合需要跨启动保存的数据,比如登录态、草稿。它的缺点也明显:频繁写 storage 会增加 IO 开销,而且它和内存对象不保持引用关系,修改后不会自动同步到页面。把 storage 当全局状态管理用,早晚会踩坑。
3.3 组件通信细节:properties、observers、triggerEvent 的参数
组件化是前端面试必考的。小程序组件题通常盯着三个点:外部属性怎么传入、内部状态怎么联动、子组件怎么向外部发消息。对应机制是 properties、observers、triggerEvent。我以计数器组件为例,外部传初始值,组件内部维护计数,每次变化都通知外部。
// components/counter/counter.js Component({ properties: { initValue: { type: Number, value: 0, observer(newVal) { // 外部属性变化时同步内部状态 this.setData({ count: newVal }); } } }, data: { count: 0 }, observers: { 'count': function (val) { console.log('count 变成', val); } }, methods: { handleTap() { this.setData({ count: this.data.count + 1 }); this.triggerEvent('change', { value: this.data.count }); } } });<!-- components/counter/counter.wxml --> <view class="counter"> <text>{{count}}</text> <button size="mini" bindtap="handleTap">+1</button> </view>逻辑说明:properties 定义外部接口,observer 在属性变化时回调;observers 监听 data 或 properties 上任何字段的变化,适合做数据联动;methods 里的 handleTap 被模板 bindtap 触发,先更新自身,再用 triggerEvent 把新值抛给外部。参数说明:triggerEvent 第二个参数是事件携带的 detail,外部在 e.detail 里读取;第三个参数可传对象,bubbles 为 true 时事件能冒泡出组件边界,composed 为 true 时能穿透组件边界进入页面节点树,面试时主动答出这两个布尔值,是明显的加分项。
页面侧接收事件用 bind:change="onCounterChange",回调里 event.detail.value 就是组件抛出的新计数。这里还有一个值得主动提的点:observers 不要做重计算,每次 setData 都会触发一遍,复杂逻辑应移到 methods 里手动调用,这个细节能体现你真的写过组件。
3.4 最小可运行的页面传参示例:把三种方案跑一遍
理论讲了三种方案,建议动手都跑一遍。我搭过一个小 Demo:A 页面有输入框和按钮,跳转到 B,B 回传一个结果,A 更新标题。EventChannel 版本跑通后,你会注意到 A 必须在 onShow 里注册监听,否则页面栈顶层还是 B,事件监听时机不对。
换成 globalData 版本再跑一遍,问题立刻浮现:B 修改 globalData 后,A 虽然还在栈里,但页面没有任何变化,必须等用户返回 A 触发 onShow 才能读到新值。这就是非响应式全局状态的局限。再换 storage 版本:A 写,B 读改,B 再写回,A 返回后重读。问题变成 IO 开销和同步时机,数据更新后页面同样不会自动感知。
三个方案跑完,你对选型的判断会从"背概念"变成"看边界":回传数据优先 EventChannel,共享低频数据用 globalData,跨启动持久化才碰 storage。面试时能把这个决策过程讲出来,比背三个优缺点要可信得多。
4. 把 20 道题拆成答题框架:从背题到会答题
一份 20 题的清单,如果逐题背答案,面试官换个问法你就卡壳。我的建议是花半小时把题分类归到几个知识方向,每个方向准备一套固定答题框架。框架的价值在于:临场遇到新题,你能把它拆成已知知识点,用熟悉的语言组织出来。这一章先讲如何分类,再给项目经验题、手写代码题、设计题三类题型的应对结构。
4.1 先把题目分类:基础、性能、工程、原理四象限
我把小程序常见面试题粗分成四类。基础题:目录结构、app.json 配置、WXML 语法、列表渲染与条件渲染、事件绑定、模板与组件的区别。性能题:setData 优化、分包加载、启动耗时、首屏渲染、图片懒加载、骨架屏。工程题:请求封装、登录态管理、多环境配置、上传发布、代码规范与自动化测试。原理题:双线程模型、生命周期、自定义组件渲染机制、事件通道。
一份 20 题的清单,分布大概是一半点落在基础,四五道落在性能,三四道落在工程,剩余两三道落在原理。这个分布说明准备重点应该压在基础和性能上,原理题用来拉档次。分类后还要合并同类项:比如"setData 有哪些问题""怎么优化 setData""为什么频繁 setData 会卡"其实是同一道题。合并完你会发现,20 道题真正需要认真准备的知识节点只有十来个,工程量一下子砍半。
4.2 项目经验题:四段式答法让面试官听懂决策过程
面试里有一类必问题:你做过的小程序项目遇到最大的难题是什么?怎么解决的?这种题表面考项目,实际考表达结构。我常用的模板是四段式:背景、方案、量化、反思。
背景一句话说清项目是什么、你负责哪块。方案列关键决策,重点说为什么这样选,而不是上来报结果。量化给前后对比,证明方案有效。反思说一个重来会做得更好的点。举个例子,被问"首屏加载慢怎么办":背景是模拟项目X,首页有商品流和多 tab,启动时主包体积偏大。方案是先拆分包,非首屏页面全部移出主包,再把首屏图片改懒加载并加骨架屏。量化是启动耗时从约 2.1 秒降到 1.2 秒。反思是当时没做分包预下载,如果重做会把详情子包提前预取,进一步减少点击后的等待。
这套结构保证每个环节经得起追问。面试官想深抠细节时,你还有"为什么用懒加载不用 CDN 优化""骨架屏怎么保证不遮挡实际内容"这类分支可以展开。
4.3 手写代码题:一个常用自定义组件的标准答案
20 题中必有手写题:实现一个自定义组件,并让它对传入数据变化做出响应。我准备的是低配版弹窗模板,面试时可以直接默写,边写边念参数作用。
// components/modal/modal.js Component({ properties: { visible: { type: Boolean, value: false }, title: { type: String, value: '' } }, data: { internalVisible: false }, observers: { visible(val) { // 用 observers 把外部属性同步到内部状态 this.setData({ internalVisible: val }); } }, methods: { close() { this.triggerEvent('close', {}, { bubbles: true }); }, confirm() { this.triggerEvent('confirm', { value: true }); } } });逻辑说明:弹窗是受控组件,外部用 visible 控制显示,内部用 internalVisible 做实际渲染。observers 监听 visible 变化,保证内外状态一致。close 和 confirm 向外抛出事件,页面通过 bind:close 和 bind:confirm 接收。参数说明:bubbles 为 true 时事件能从组件冒泡到页面,适合弹窗这类全局交互组件;triggerEvent 的 detail 尽量使用对象结构,后续扩展字段不用改事件名。
手写时三个细节容易丢分:第一,properties 里 type 必须写,否则运行时会报警告;第二,observers 回调不要用箭头函数,this 指向会偏;第三,事件名在小程序模板里推荐 kebab-case 写法,但 triggerEvent 里传的是 camelCase 风格,这个差异要能说明白。这些点会让面试官确认你写的代码真的上过线,而不是纸面上看着对。
4.4 设计题追问:性能优化方案之间的决策顺序
面试官问"用户量上来了,你怎么优化小程序",期待的不是一个孤立方案,而是一套决策思路。我习惯按"定位、方案、验证"三步走。先看线上性能数据,启动慢看主包体积和启动脚本,页面卡看 setData 频率与渲染耗时,白屏久看接口响应和缓存命中率。没有数据支撑的优化方案,面试官会一路追问到你答不上来。
然后才是方案:启动慢可以分包、预下载、精简启动逻辑;页面卡可以合并 setData、降低组件复杂度、引入虚拟列表;接口慢可以加缓存、做预请求、优化并发。最后是验证:上线前用性能工具做前后对比,上线后看线上数据和用户反馈。这里有个容易踩的认知误区:骨架屏不是性能方案,只是体感优化,它解决白屏焦虑,不解决加载速度。面试时能说清这个区别,说明你不会被一两个热词带着走。
5. 小程序面试避坑与常见问题排查:五个翻车现场
小程序开发的坑,在面试里会变成更隐蔽的追问。有些问题只靠背书发现不了,因为它在真机上才出现;有些问题明明能避开,却因为不了解原因反复踩。这一章写五条高频翻车现场,每条按现象、原因、解决三步给清楚,你对照排查即可。
5.1 现象:setData 之后立刻查询节点还是旧值
现象是执行完 setData 后马上用 createSelectorQuery 选节点尺寸,拿到的是旧值。原因是视图渲染异步,节点尺寸必须等渲染完成后才能查询。解决是把依赖新视图的查询放到 setData 回调里,或等 wx.nextTick 执行后再查。
// 出错写法 this.setData({ height: newHeight }); this.createSelectorQuery() .select('#box') .boundingClientRect(rect => { console.log(rect.height); // 旧值 }) .exec(); // 正确写法 this.setData({ height: newHeight }, () => { this.createSelectorQuery() .select('#box') .boundingClientRect(rect => { console.log(rect.height); // 新值 }) .exec(); });逻辑说明:setData 回调触发说明渲染线程已完成本次更新,此时查询节点才是安全的。面试时被问"为什么 setData 后拿不到节点高度",直接讲清"双轨更新"逻辑就行。
5.2 现象:组件事件跨页面后就丢了
现象是页面 A 里组件触发事件,监听回调还没执行,用户就跳到页面 B,返回后发现回调丢了。原因是事件监听是运行时绑定在当前组件实例上的,页面卸载时组件销毁,监听一并回收。解决是跨页面数据回传不要依赖组件事件链,改用 EventChannel 或 globalData;页面内有异步回调要等的话,在 onUnload 里做取消和防泄漏处理。
5.3 现象:开启独立分包后,公共方法突然不可用
现象是某开发者把部分页面挪进独立分包后,这些页面里访问 app.globalData 或公共工具函数时直接报错,逻辑层找不到定义。原因是独立分包运行时,逻辑层与主包不是同一个 JavaScript 上下文,两者不共享全局代码和 globalData。解决是在设计分包时想清楚边界:独立分包页面要自包含它依赖的公共逻辑,不能暗地里依赖主包模块。面试时主动提到"分包不是目录移动,得按依赖关系重新梳理",比单纯说"把页面移进 subpackages"更有工程分。
5.4 现象:真机正常,开发者工具里白屏或报 script error
现象是同一份代码真机预览没问题,开发者工具却编译报错甚至白屏。原因大概率是工具的本地基础库版本与真机不一致,或者工具缓存了旧编译产物。解决顺序:先清缓存重新编译,再检查项目详情里基础库版本,最后看报错堆栈定位文件。不要一上来就怀疑业务代码,工具缓存的玄学问题占比很大。面试里被问到"真机调试和工具调试的差异",能说出基础库版本这个关键词就已经领先。
提示:清缓存的操作路径在开发者工具菜单栏里选"清缓存 → 全部清除",然后重新编译,大部分诡异报错会自己消失。
5.5 现象:页面销毁后 setData 引发隐蔽告警
现象是页面 onUnload 后,页面里某个异步请求的回调还在执行,回调里调 setData,控制台出现"页面不存在"之类的告警或被静默忽略。原因很直接:异步请求没有随页面销毁取消,回调继续跑,页面实例却已经没了。解决是在 onUnload 里置一个销毁标记,请求回调里先判断标记再决定要不要 setData;更彻底的做法是封装请求层,支持以页面为单位取消未决请求。这类问题面试官喜欢放在"你踩过什么坑"里问,按现象、原因、解决三步讲,思路最清晰。
6. 把 20 道面试题变成自查表:一个有效期不止一场面试的准备技巧
这一章分享我亲测有效的准备方法:不按题号背题,而是把 20 道题映射到知识树,再准备一个三分钟能写完的手写 Demo,面试结束立刻复盘。这套方法不限于小程序,任何前端方向都能复用。
6.1 从题目到知识树:三个问题完成归因
拿到任何一道题,先问自己三个问题:它在考原理、考 API,还是考工程权衡?它落在哪棵知识树上——架构、生命周期、通信、性能、工程哪一支?如果面试官追问一步,会追到哪个节点?三个问题都答得上,这道题就不是孤立题目,而是知识树上的一个枝节。我把小程序知识树分成五条主枝:架构与生命周期、数据通信与状态、性能优化与启动、工程化与发布、组件与复用。20 道题归位后,真正需要重点准备的只剩十道左右,其余全是主枝上的变体。
6.2 三分钟手写 Demo:熟到不用想的组件模板
面试现场手写代码,拼的不是灵光一闪,而是肌肉记忆。准备一个不带第三方依赖的组件模板,把 properties、observers、triggerEvent 三个机制都覆盖到,练到闭眼能写。这样就算面试题和模板不完全一样,你也能基于模板快速改出可用版本。写的时候口头同步讲每个参数的意义,比写完沉默展示代码块加分得多。
Component({ properties: { value: Number }, data: {}, observers: { value(v) { console.log('外部 value 变化:', v); } }, methods: { onIncrease() { this.triggerEvent('change', { value: (this.properties.value || 0) + 1 }); } } });逻辑说明:模板只依赖官方组件能力,没有额外库,现场快速写出来不会暴露短板。参数说明:方法里读传入值用 this.properties.value 而不是 this.data.value,因为同名数据在 data 里只算内部状态,最终以 properties 传入值为准。这个细节很多人忽略,主动说出来会让面试官确认你理解组件数据流,而不是背模板。
6.3 面试后的复盘清单:把遗憾变成下一题的必对项
每次面试结束,我会花二十分钟复盘。清单只有四项:哪些题背过但没答全;哪些题被追问后卡壳;哪些知识点完全没准备到;哪些回答暴露了经验边界。针对后两项,我会先查官方文档把原理重新读一遍,再回到知识树更新节点图。这套"面试-复盘-补树"的循环,能让同一方向上的题越面越熟,而不是面完就忘。
我的习惯是把每次没答好的题变成一道新的自测题,记录问题本身和我的卡壳点,下一次面试前快速过一遍。坚持到第三轮时,你会发现题库里的题开始"重复",因为你已经把主枝上的知识都加固过,换问法也逃不出知识树的范围。希望这套方法能真实帮到你,祝你准备路上少些翻车,多些确定的收获。
本文还有配套的精品资源,点击获取