字节前端实习一面二面凉经 10月份
字节一面复盘
三个部分,自我介绍、技术知识考察、实战考察(如果时间允许,实际没有)流程是问简历上的项目,基本是从上往下看到什么问什么,根据简历问到了vue、WXML、CSS、深度学习、色彩原理、图层蒙版的简单知识。
项目问题
- 你后面也写过,WXML, 也写过传统的前端,对吧?对你觉得这个WXML和HTML有什么区别呢? 答:微信小程序接近vue的思想,组件化,库管理更方便。 更好的答案(为什么开发wxml而不使用html):
- 底层优化:WXML 是为小程序环境量身定制的,它与 WXSS 和 JavaScript 的结合更加高效。
- 功能取舍:标签更轻量级,解析和编译开销小
- 安全:屏蔽了iframe href等风险标签和属性,堵住了安全漏洞和违规行为
- 封闭:构建了封闭完整的技术生态,一个是方便商业化和审核管理,一个是建立了微信生态
- 前瞻性:要去做小程序之间唤起、与微信共享联系人等需要与微信深度结合的功能
- 你有没有想过为什么微信要自己开发,没有直接用传统的前端技术栈? 我理解成了为什么微信小程序不直接用vue语言,实际上面试官想问为什么微信小程序要存在而不是用原生html。 答:微信想有封闭和安全的生态,方便审查。
- (面试官向我科普上面问题的答案)你写HTML的时候,有没有尝试过调一些系统级的API?你有没有想过这个HTML里怎么唤起外部程序,包括电脑和手机上?如果我想要自己更拓展一些,我想要有一些原生的交互,那这个HTML可以实现吗?比如我想要调起微信,我想要在微信里选一个联系人呢? 答:没有研究过。
- 其实这就是微信WXML的一个他要解决的问题之一。大家可以通过一套自己的语言来实现和微信的交互。微信是一个native,还可以调用系统的各种底层的能力,所以这也是其中的一个优势。
- 你的小程序“树上导航”他解决的主要问题是什么?用户痛点是什么? 答:我们学校四个校区,我这边的校区比较偏僻,不管是百度地图、腾讯地图还是高德地图,它在我们的校园内部它的信息是不准确的。就是说它大部分标的地点是错误的。我们也向这些地图软件反馈过信息,但是要反馈的地点会非常多,审核流程非常复杂,采纳率也很低,我们希望有一个更加好用的地图给新生去看,最好是提供校内导航功能,既然没有那为什么不做一个呢?于是我们自己开始了这个项目。这个项目上线之后收到新生反馈是说很有帮助,每年都会新增有200多用户量。
- 你在这个项目中具体做了什么事呢? 优化后的答:项目大部分代码都是我写的,首先是负责项目的寻路算法,用了djisktra算法和Astar算法;还有图的储存机制是我负责设计的,他不可能用百度那种道路级的这么复杂数据结构,我们就用了简单一点的带权边。项目的前端代码都是我敲的,包括页面设计和实现。(马后炮:我还负责需求收集,去调研了同学们对于校内地点和功能的需要)还有那个地图数据的采集,也是我负责去做多次调试的。他需要的那个坐标数据,一开始是没有的,而且我们也试过多家的小程序去做那个地图采集,然后发现他们坐标系不一样,然后也是我负责去调整那个坐标系,然后多次的重新去踩点,把那个数据给做好了。
- OK, 那你刚才提到了你会修正一些数据,会采集这个道路的数据是吗?那咱们具体是怎么采集的呢?你怎么找到某一个节点的坐标呢? 优化过的答:我们用过很多方案,节点需要的是经纬度坐标,开始我们在百度地图的开放平台上试过用鼠标,在卫星地图上去选取坐标,发现这个根本不准。地图显示和实际位置是有误差的,我们校园内导航要求的精度有比较高,所以考虑我们自己去走一遍。开始用第三方的坐标采集小程序,这里因为百度和腾讯的坐标系不一样又换了几次小程序,但是实际踩到的坐标是抖动的,直线道路采出来是扭曲的。我们认为这是第三方小程序的精度限制,最后我们做了一个调试页面,我们用小程序本身的map组件去进行定位和记录节点,点一个按钮就会采集坐标加入数组,我们会打几百个点回去统一导出,然后修正连接的点。
- 那咱们是怎么决定要踩哪些点的呢?咱们这个节点都是怎么选的呢? 答:我们自己会先列出一个表格,按生活、学习、餐饮、景点去归类校园内的地点,尽量把大大小小的地点都包括进去。最开始是项目成员先写,后面去在微信私下问或者公开问卷去向同学征集我们遗漏的地点。
- OK, 我对这个项目有一些了解了,那咱们看一下下一个,我看你这个基于深度学习脑电信号的抑郁症检测系统,这个项目里你提到了前端使用的vue3。为什么这个项目要使用vue3? (这个有更好的回答方法,我回答的没有深度)原生HTML写样式太难太慢,在前端框架中听说vue比React好上手,由于时间紧促选择了vue。
- 你认为原生html写样式具体繁琐在哪里呢? 答:书写动画比较繁琐;vue的样式库多,模块化也更好而且我们考虑到原来的项目里面有部分模块它是需要复用的,所以就使用了vue。
前端技术问题
- 你刚才提到vue的模块的话,那vue在编译一个组件的时候,你这个组件里会写一些style对吧?那这些的style这个css它在编译的时候是会原样的插入到最后写的HTML中吗? 答:不会,会经过编译器,比如webpack和vue自带的编译器会剔除掉多余的样式代码。
- 你知道vue中有个style scope特性,写了scope以后,这个style只对这个template里面的属性的元素生效。请问这个你有了解过是怎么实现的吗?它为什么会影响到其他的部件? 答:我知道有这个特性,具体怎么实现还没看。(面试官提示了一下:类选择器就是一个普通字符串...)有印象,就是他会去好像是对那个类名会加后缀,然后就用了额外的类选择器。
- 对的,你还了解过其他的这种把CSS限定在某一个区域内的手段吗? 除了vue的这套实现之外。 答:没有。(面试官ok,这个不是很重要) 补充: CSS Modules,与vue的style module是类似的机制。shadow DOM是原生浏览器组件,可以封装DOM结构和样式。
- 介绍一下你的项目怎么进行cookie的模拟? 答:Cookie是储存数据或者说认证身份的一种手段。对于服务器来说,你通过这个cookie它来识别你是哪一个用户,或者说它旧的很早期的时候,他被用作账户的认证的一种手段。不过现在可能被更好的一些技术代替了。然后我们这边他的cookie主要是用了用于绕过B站的那个反爬虫机制,所以用了这个cookie,最重要的是浏览器头伪装和B站用户的cookie。
- 你还有了解过其他的前端的数据存储的方式吗? 答:我经常比较使用的是那个web storage,就是本地的储存,可以储存MB级的数据,剩下的没有怎么了解过。
- 你有了解过local storage和session storage的区别吗? 没有。 两者都是 Web Storage API 提供的客户端存储机制,用于在浏览器中存储键值对数据。它们的核心区别在于生命周期和作用域: 1. 生命周期 localStorage
- 数据永久存储,除非手动清除(通过代码、浏览器设置或清除缓存)。
- 即使关闭浏览器或重启设备,数据依然保留。 sessionStorage
- 数据仅在当前会话期间有效(即当前浏览器标签页或窗口)。
- 关闭标签页或窗口后,数据自动清除。
- 刷新页面不会丢失数据。 2. 作用域 localStorage 同源(相同协议、域名、端口)的所有标签页和窗口共享同一份数据。 sessionStorage 数据仅限当前标签页或窗口,同源的其他标签页无法访问。 3. 共同点 存储容量均为约 5MB(不同浏览器可能略有差异)。 仅能存储字符串类型数据,复杂数据需通过 JSON.stringify()转换。 通过 setItem()、getItem()、removeItem()等方法操作。 受同源策略限制,不同源的数据互不可见。
- 为什么需要有一个cookie再有一个storage? 答:cookie的它们两个的用途是不一样的。Storage它应用是本地储存,它主要将数据储存在客户端本地,他是为了减少资源加载造成的负担,就是重复加载造成的负担。但是cookie用作就是给浏览器去用。首先它的储存数据的量级跟那个传,储存数据的允许的大小,跟平常使用的大小都会比较小。然后它储存的是类似配置,就是网站的选项配置之类的一些东西。 更好的答: cookie的它们两个的用途是不一样的。cookie用来维持用户登录状态,每次请求都会带上cookie,所以容量也很小,4KB。Storage它应用是本地储存,它主要将用户配置、缓存、离线数据储存在客户端本地,他是为了减少资源重复加载造成的负担。storage的容量有MB级,适合做缓存,放非敏感的数据。
- (面试官可能觉得回答没有到点子上,换话题了)你的项目为什么会用axios?axios解决了什么问题? 答:用于向后端发送API,以及做统一拦截器方便调试。
- 听说过window.fetch吗? 为什么不用这个?(没有用过,又开始跟我科普)这绝大部分情况下使用windows上的fetch就OK了。只有在一种情况下是你上传文件的进度。你要监听上传文件的进度的时候,你需要用到你需要用到,那其他的所有的情况都可以。现在的前端开发基本上有window.fetch就够。可能它对于前后端重构的项目它的帮助会比较大,它可以抹平一些浏览器和服务器的之间的差距。
- 前后端同构的JAVA+thyleaf应用和前后端异构(分离)的项目你都做过,这两种项目对比下来你有什么感受吗?他们两个的前后端协同方式是不同的,那你对这两种开发的流程体验有什么主观的感受? 我主观的感受是,如果它是中后端的一个项目,他用到了java,那么它会后端上来说会非常的重。可能也是因为我当前接触到的项目,它并没有这么重视后端的数据安全和那种防黑客防泄露的那种数据。所以对于我来说,目前的后端是太重了。如果你说你要用一个非异步的项目,你用java,那你必须上spring boot去去跑。这样的话就是你你会多很多后端方面的学习成本。这样的话对于我来研究前端的话会比较本末倒置。然后其次就是我选前后端分离,就是因为后端用一些比较简单的功能就已经够了,所以前后端分离会省一些功夫。 标答:
渲染方式 | 服务端生成 HTML,直接返回给浏览器(SSR) | 前端通过 JS 框架渲染页面(CSR),后端提供 API 数据 |
技术栈组合 | 后端模板引擎(如 Thymeleaf/JSP) + 后端逻辑控制视图 | 后端提供 RESTful API / GraphQL,前端用 Vue/React/Angular 等 |
数据交互 | 后端直接把数据嵌入到模板中,一起返回 HTML | 前端通过 Ajax/Fetch/axios 请求后端接口获取 JSON 数据 |
页面跳转 | 服务端路由,页面跳转由后端控制(如 Controller 返回视图名) | 前端路由,页面切换由前端 JS 控制(如 React Router/Vue Router) |
开发角色耦合度 | 前后端通常强耦合,后端往往也要懂模板,前端可能较弱或偏静态 | 前后端职责清晰分离,后端提供接口,前端消费数据 |
SEO 友好性 | ✅ 天然友好,因为服务端直接返回完整 HTML | ❌ 需要额外处理(如 SSR 或预渲染)才友好 |
首屏加载速度 | ✅ 通常较快,因为 HTML 是服务端渲染好的 | ⚠️ 可能较慢(尤其首次加载),需要等待 JS 加载和渲染 |
开发体验/工具链 | 较传统,IDE 支持好,调试直观 | 更现代化,依赖 npm、webpack、vite、各种构建工具 |
✅ 如果你追求 快速交付、简单业务、强 SEO、低前端复杂度 → 前后端同构(Thymeleaf 等)更合适
- 我在做政府、企业官网、内部 CMS 等项目时,用 Thymeleaf 开发非常高效,页面和数据一步到位,不用操心前端构建、接口联调等问题。
- 对于小型团队或全栈开发者来说,这种模式可以减少沟通成本,一个人就能搞定前后端。
- 但一旦业务复杂起来,比如需要复杂的交互、多角色权限、动态表单、图表等,继续用 Thymeleaf 就会显得吃力,代码难以维护,前端体验也上不去。
✅ 如果你追求 高交互、高用户体验、团队协作、技术深度、可扩展性 → 前后端分离更香
- 在我做复杂后台系统、数据可视化平台、SaaS 应用的时候,前后端分离让前端可以真正发挥出 Vue/React 的优势,做出流畅、动态、可维护的界面。
- 前后端通过 API 契约协作,职责清晰,后端可以更专注于领域建模和业务逻辑,而不被视图层束缚。
- 但前提是团队要有一定的前端工程化能力,接口管理、文档规范、Mock 工具、联调流程都要规范,否则初期会很痛苦,沟通成本高。
🤝 总结一下两者的本质差异带来的主观体验:
开发速度(简单项目) | 快,上手简单 | 较慢,初期配置和联调成本高 |
交互与用户体验 | 一般,受限较多 | 强,可实现复杂交互和动态 UI |
前后端耦合度 | 高,后端常常也要写前端相关代码 | 低,职责清晰,可并行开发 |
SEO | 好 | 需额外处理 |
首屏性能 | 好 | 一般(需优化) |
技术发挥空间 | 前端受限 | 前端能充分发挥现代框架能力 |
适合团队 | 小团队 / 全栈 / 快速迭代 | 中大型团队 / 专业分工 |
- 我看到你的专业技能里面写到的属性的开发。请问什么是敏捷开发? 敏捷开发是就是先去把一个原型去做出来。就是他在软件工程里面,他要求你先让那个车子跑起来,而不是让那个车子好看。先去比较快的做出来一个项目,去给到客户去使用,让他们得到反馈。然后再拿到这个反馈,再去把这个项目有针对性的去修改。这样的开发方式是敏捷的开发。
- 你和其他人在合作的过程中,你是怎么用git的? (有更好更专业的流程,这个时候已经脑子一团浆糊了,没有持续面试过这么久)按不同模块同时开发,开分别的branch,偶尔处理单文件冲突。
- 遇到单文件冲突会怎么解决? 发生同一个文件的冲突的话,一般会有很多种原因。一种是可能他就是单纯的提交错误了。他把只有他电脑上能使用的配置文件给提交了上来。而且他提交了,这个时候我就会在我电脑上面我会去找我的get历史,然后把我自己的配置文件给回荡回来,然后把他的文件,就是把他提交上的东西给覆盖掉。或者说如果这个文件变动可以撤销它的话,那我们可以直接将它revert。如果它不太好修改的话,我就会直接把它那个文件打开,手动处理每一处冲突标记。
- 你刚才提到了revert。revert的时候,是不是会把提交的所有文件都撤回? 我回答的是。面试官叫我回去查一下怎么revert单个文件,但是查到git revert命令确实只能撤回整个提交......要撤回单一文件要用git restore 或者git checkout
- 从输入URL到页面显示都发生了什么?你能把这个链路简单的介绍一下吗? 输入URl之后,浏览器会对这个UR1进行解析。比如说他的协议,它的主机,它的端口,还有它的路径,然后它会根据这个协议去找对应的协议。比如HTTP,他就会走HTTP的处理,然后他先去找DNS,把这个域名给找发送过去DNS服务器得到IP,然后往这个IP去发送请求。如果你只是在浏览器输入的话,那它就是get这个页面。然后他发送过去那个报文,然后等待那个浏览器发回来这个报文,然后就把这个拿到的页面,就是通常是HTML,然后去用浏览器渲染。 优化后的答:(考察七层网络模型的结构) 1.浏览器解析url的协议、主机名、端口、地址; 1.5.浏览器检查缓存,如果存在而且新鲜(上次拿到缓存后经过的时间小于缓存的Cahe-control 2.请求dns服务器获取ip地址; 3.建立tcp连接; 4.https握手; 5.发送http请求GET, 请求会先封装成tcp段, 再封装成ip数据包, 最后在链路层封装层帧, 最后由物理层发出去 6.服务器处理请求,返回对应的数据 7.浏览器接收到响应, 开始渲染页面, 执行js代码 8.显示页面
- 那你能简单介绍一下CSS的盒子模型吗?一个元素的尺寸是怎么确定的?它和其他元素之间的位置关系是怎么确定?
(不是弹性盒子,愣住了没有回答)
标答:每个HTML元素都是一个矩形的盒子,有内容区、内边距、边框、外边距组成。默认的W3C标准的盒子模型
box-sizing:content-box;的宽高仅指内容区,IE盒子模型box-sizing:border-box;的宽高指content + padding + border的宽高。 - (开始问很基础的)你怎么设置一个元素的长宽高?我想要加一个描边儿,要怎么做呢?内外边距有没有什么专门的属性来确定? 正常回答
- OK,那CSS有什么常用的布局方式吗? 答:static flex grid absolute fixed sticky
- 你能简单介绍一下flex和grid吗?他们都用在什么场景下? Flexbox 是一维布局系统,适合做局部布局,比如导航栏组件。Grid 是二维布局系统,通常用于整个页面的规划。 (没有很好地回答他们的区别)
- flex布局会影响子元素的尺寸吗?会影响自己的尺寸吗?
标答:会的。父元素
display:flex;时,子项默认值是flex: 0 1 auto;也就是说,尽可能收缩以适应内容(flex-shrink: 1),但不会自动撑满可用空间。
|
| 不放大 :子项 不会自动扩展 去占据剩余空间 |
|
| 允许缩小 :如果空间不足,子项 可以收缩 以适应容器 |
|
| 初始大小基于内容自然大小或指定的 width/height ,指定其他值的时候,认为元素在主轴方向的尺寸以该值为基准,再处理grow\shrink |
把 Flex 子项想象成小朋友去分糖果(剩余空间):
-
flex-basis: auto:每个小朋友先根据自己的胃口(内容大小)拿一部分糖果,然后剩下的再大家一起抢。 -
flex-basis: 0px:所有小朋友一开始手里都没有糖果,然后大家完全公平地抢所有糖果(最公平的等分)。 -
flex-basis: 100px:每个小朋友一开始就有 100 颗糖果,然后再去抢剩下的或者吐出来。
简历上关于其他领域的知识考察
- 我看到你里面说实现了多模态的AI。那你这个多模态是怎么实现的? 多模态其实它这个定义不太一样。因为我们这里的多模态说的是医学上的多模态,他意思是说他同时处理了脑电波信号跟眼电波信号,它把这两种信号称为多模态。但是在我看来的话,他们都是一种电信号,他们在时间序列上面就是有波动,但是在医学上面他们是可以叫做多模态的。
- 那你有了解过现在比较流行的这些AI模型都有哪些? AI模型有很多种,你像自然语言处理有NLP模型,然后有普通的深度学习模型,机器学习模型,语音模型和文生图模型。
- 你有了解过ChatGPT或者deep seek背后的模型是什么架构?(Transformer架构)能简单介绍一下吗? Transformers的架构简单介绍一下,它是自注意力机制。就是它的作者发表的论文是attention is all you need。它主要是使用了神经网络,它在不同词之间,它使用自注意力去预测那个词之间的出现的概率。里面具体的那个组成的话我看过,不过我忘记了。
- OK, 那你有了解过midjourney或者是剪映他们这些文生图的模型背后的是什么架构?简单介绍下diffusion模型? 它是扩散的意思。它的原理是生成一张噪声图片,然后多通过很多个层去对这些噪点进行扩散,去预测它下一个这个噪点附近下一步应该是什么颜色,然后一层一层的扩散上去,最终得到一张连续的图片。
- 我看到你的校园经历写了这个做海报。你使用过PS吗?你能简单介绍一下什么是蒙版吗? 蒙版,跟遮罩是比较像的。就是它决定了这一个图层它显不显示以及根据蒙版的灰度决定显示多少,蒙版越白显示出来的越完全。
- 我了解了,你能简单介绍一下什么是调整图层吗?为什么要用调整图层而不是直接修改图片? 用处就是用来打滤镜的,它会对它下面的图层进行整体的变动。比如说我在用PR的时候,我经常会套上一个调整图层,然后在上面采用滤镜做那个色彩调整,还有效果。不修改图片是因为我们有时候需要去修改那个图片的来源,就是我们需要把它换成别的图片。这样子的话就是我们很多时候他追求的是一系列的效果预设,而不是说对那个图片进行修改。
- 你知道哪些色彩模式?我说的色彩模式是指比如RGB。你提到这几种中最符合人眼成像原理的是哪种? RGB,HSL和CMYK。HSL是最符合的。 更好的回答:
RGB | Red, Green, Blue<br>(红、绿、蓝) | 加色模型 <br>色光叠加 | 所有屏幕显示 <br>(网页、UI、视频、游戏) | R(红)、G(绿)、B(蓝) <br>每个通道通常为0-255级 | - 色彩丰富鲜艳<br>- 是数字设计的起点<br>- 设备相关 (不同显示器效果不同) |
CMYK | Cyan, Magenta, Yellow, Key<br>(青、品红、黄、黑) | 减色模型 <br>油墨吸收 | 所有印刷品 <br>(画册、杂志、包装) | C(青)、M(品红)、Y(黄)、K(黑) <br>每个通道通常为0-100%油墨量 | - 色域通常比RGB窄<br>- 专为印刷设计,转换自RGB时会失色<br>- 设备相关 (不同印刷机效果不同) |
HSB/HSV | Hue, Saturation, Brightness/Value<br>(色相、饱和度、亮度/明度) | 基于视觉直觉 | 软件调色 <br>(最符合人类选色习惯) | H(色相) :0°-360°<br> S(饱和度) :0%-100%<br> B/V(亮度) :0%-100% | - 纯色出现在 B/V=100% 时 <br>- 饱和度降为0得到白色(当B/V=100%)或灰色<br>- 非常直观,易于挑选颜色 |
HSL (不在PS拾色器里面) | Hue, Saturation, Lightness<br>(色相、饱和度、亮度) | 基于视觉直觉 | 软件调色、网页设计 <br>(CSS支持) | H(色相) :0°-360°<br> S(饱和度) :0%-100%<br> L(亮度) :0%-100% | - 纯色出现在 L=50% 时 <br>- L=100% 为白色,L=0% 为黑色<br>- 在创建同色系明暗变体时比HSB更对称 |
LAB | CIEL*a*b<br>(无中文通用简称) | 与设备无关 <br>基于人眼视觉感知 | 专业色彩转换、高级图像编辑 | L(明度) :0-100(黑到白)<br> a :绿-洋红轴<br> b :蓝-黄轴 | - 色域最广 ,包含人眼可见的所有颜色<br>- 明度(L)与颜色信息(a, b) 完全分离 ,可单独调整<br>- 常作为RGB与CMYK转换的 中间桥梁 |
HSB/HSV vs. HSL:
HSB 和 HSL 在字面意思上是一样的:
- H 指的是色相(Hue),就是颜色名称,例如“红色”、“蓝色”;
- S 指的是饱和度(Saturation),即颜色的纯度;
- L(Lightness) 和 B(Brightness)是明度,颜色的明亮程度
在原理和表现上,HSL和HSB 中的 H(色相)完全一致,但二者的S(饱和度)、L 和 B(明度 )不一样:
- HSB 中的 S 控制纯色中混入白色的量,值越大,白色越少,颜色越纯;
- HSB 中的 B 控制纯色中混入黑色的量,值越大,黑色越少,明度越高
- HSL 中的 S 和黑白没有关系,饱和度不控制颜色中混入黑白的多寡;
- HSL 中的 L 控制纯色中的混入的黑白两种颜色。
![[attachments/Pasted image 20251019164407.png]]8. 你有了解过什么设计原则吗?比如亲密性之类的?我说没有。这里是答案:设计的四大基本原则(CRAP原则)
- 对比核心思想:避免页面上的元素仅仅是相似,如果它们不同,就让他们截然不同。目的:创造视觉焦点、增强视觉效果、组织信息层次。对比能第一时间吸引读者的注意力,引导他们先看哪里,后看哪里。应用场景:标题与正文字号/字重的强烈对比;主要按钮与次要按钮的颜色对比;不同信息板块的背景色对比。
- 重复* 核心思想:让设计中的视觉要素在整个作品中重复出现。* 目的:统一作品风格,增强整体感和一致性。* 应用场景:企业VI中的Logo、标准色、特定字体在整个宣传物料中重复出现;报告中相同级别的标题使用相同的样式;网页中相同的按钮样式、图标风格。
- 对齐* 核心思想:任何元素都不能在页面上随意安放,每个元素都应当与页面上的另一个元素有某种视觉联系。* 目的:创造秩序,使页面统一而有条理,看起来更精致、更专业。* 应用场景:文本的左对齐、右对齐或居中对齐;图片与文字的边缘对齐;多个元素通过一条看不见的“对齐线”建立关联。
- 亲密性* 核心思想:将相关的项组织在一起,让它们物理上相互靠近。不相关的项则分开。* 目的:实现信息的归组,使内容结构更清晰,逻辑关系一目了然,减少混乱。* 应用场景:图片和它的说明文字应该紧挨在一起;一个表单的标题、输入框和标签应该是一个亲密组,与其他表单项保持距离。
除了这四大基础原则,还有其他一些非常重要的设计原则:
- 留白指设计元素之间的空白区域。留白不是“浪费空间”,而是用来塑造高级感、呼吸感和聚焦视线的重要工具。充足的留白能让核心内容更突出。
- 平衡指元素在页面上的视觉重量分布。可以是对称的(稳定、正式),也可以是不对称的(动态、有趣),但整体上要达到一种平衡感,不会让人感觉一头重一头轻。
- 层次通过调整元素的大小、颜色、位置等,引导用户以特定的顺序接收信息。最重要的信息最突出(比如最大的字号、最显眼的颜色)。
- 简约经典原则“如无必要,勿增实体”。只保留必要的元素,去除一切不必要的装饰和干扰,让信息传达更高效。苹果公司的设计就是典范。
反问环节
- 这个岗位他用的是vue吗?还是说他会需要更加新的一些技术栈? 答:其实没有什么新旧之说,它只是一个选择。在字节里边基本上都是用的react。不过对于应届生的要求是没有这个框架要求的。所以你即使是从来没有用过框架,你也是OK的进来再学就行,这个不用担心。
- 那第二个是说,我想问一下就是说有没有建议去在前端这边学习什么路径呢?就是他未来的趋势,他有没有一些建议可以去针对的去学,预先去钻研一下。 答:你突然这么问我,我可能也没有什么很完美的答案。你说我直观的感受是你可能还是在项目中去练习会比较好。你可以学习其他人的项目,比如说有一些开源的,最好是从页面展示开始,你不要一上来就看那种很大的那些WebApp。你就看一个简单的,我比如说一个公司的官网,那他是怎么写这个CSS,然后它的HTML是怎么去怎么构建。如果能找到开源项目的话,你看看他的源码,他的react或Vue的文件是怎么组织的,他为什么要这么组织?他在他从源码到最终你看到的HTML中间,他经过了什么?最好你不需要特别详细的去学习。但你要理解有这个过程以后,你在AI编程的过程中,如果AI出了什么bug,你可以去准确的定位,然后你可以去帮助他去修复,这样就OK了。好。可能同学的CSS的能力稍微欠缺一些。不过这个不是什么大问题,反正后面可以再深入了解一下CSS相关的内容。好啊,那咱们本次面试就先到这里,咱们的面试结果和后续的如果有后续安排的话,会有HR晚一些统一传达给同学。
二面跟一面有什么区别?着重问什么?
二面通常是隔级leader面试,一面是直级leader。一面的leader一般是你的直接负责人,注重对于业务和能力的考察。二面,leader的leader会更注重上层的因素,包括人格、思维、眼界。
- 你在他的团队里面是什么样的位置?有没有值得培养的空间?
- (50%)你在过去的项目中有没有对用户、项目价值、业务风险的前瞻性思考?
- (30%)对于这个岗位的看法、对竞品的看法、对行业的思考?
- (20%)人品,适不适合自己的团队? 也有另一种说法是二面才是技术面😭 实际上感觉二面是公式化八股,有50%是拷打你的技术深度和广度,50%是问你的行业观念和AI观念,而且问题多且泛,没有提前思考过的根本说不出口
字节二面复盘
自我介绍2分钟+提问28分钟+算法题30分钟提问多是开放性问题,算法题简单,但是10分钟要写出来比较难。
我先问一些简单基础的问题,然后后边能围绕你的项目做一些讨论,最后可能有些编程题。
技术深度和行业眼界拷打
- 你们项目打包后的资源是怎么部署的?怎么让外部用户访问的? 我们用webpack打包。在项目后来的上线阶段,我们把项目的后端和前端都放在devbox或者阿里云服务器上面,配置nginx,开放域名和端口。
- 打包好的HTML是谁托管的?是在你刚刚说的那个项目(Fastapi)上吗? 打包好的前端资源是静态的。他会放在后端中挂载,后端是python的Fastapi库。托管是我们租用的云服务器进行项目托管。
- python只负责做这个事情吗?还是包括api一起? 也负责响应api。
- 你们的项目是打包成标准的webpack资源包进行挂载。你觉得这样会有什么问题吗? (我不会答,1.单点挂载会导致加载慢、缓存利用率低、FCP长 2.静态的资源包容易被缓存导致用户刷新拿不到服务器更新后的页面) 项目的相对路径和绝对路径会发生改变。
- 在fast API的那个库里,他对比如说模板静态资源这些读取会有缓存机制吗? 有。
- 比如说我想更新我打包后的那个文件,然后你有什么办法能让用户立刻看到新的吗? 我作为开发者会在F12中勾选停用缓存。普通用户会在cookie里面写no-chache。
- 哪些文件会写nochache? 主要是js(瞎猜的,正确答案是html文件,尤其是index.html)
- 有了解过CDN吗? 没有
- 所有的编程语言里你最熟悉的是哪个? c++
- 在JS里如何区分数组、对象、函数、日期这些数据类型? (标准的八股,背了但是忘记了Array.isArray()) typeof Object.prototype.toString.call() instanceof Array.isArray()
- 前3种方式,他们之间区别是什么?简单讲一下。
(回答的很烂,标答在下面)
typeof、Object.prototype.toString.call()和instanceof是 JavaScript 中用于类型检查的三种不同方法,它们的用途和行为有显著区别:
typeof
- 作用:返回一个值的基本数据类型(字符串形式)。
- 特点:对原始类型(如 number、string、boolean、undefined、symbol、bigint)有效。对 null会错误地返回 "object"(历史遗留问题)。对函数返回 "function",对其他对象(包括数组、日期等)统一返回 "object"。
- 示例:
Object.prototype.toString.call()
- 作用:精确获取值的内部类型标签(最可靠的类型判断方法)。
- 特点:调用 Object.prototype.toString方法并传入目标值(通过 call绑定 this),返回格式为 [object Type]的字符串。可以区分所有内置类型(如 Array、Date、RegExp等)和自定义对象。
- 示例:
- 用途:需要精确判断类型时(如区分数组和普通对象)。
instanceof
- 作用:检查一个对象是否是某个构造函数的实例(基于原型链)。
- 特点:用于检测对象的原型链中是否包含构造函数的 prototype属性。仅适用于对象,不适用于原始类型(如 42 instanceof Number返回 false)。在跨框架(iframe)时可能失效(因为构造函数来自不同全局环境)。
- 示例:
[] instanceof Array; // true
{} instanceof Object; // true
new Date() instanceof Date; // true
"hello" instanceof String; // false (原始类型不是对象)
new String("hello") instanceof String; // true (对象包装器)
核心区别总结:
| 基本数据类型 | ❌(都返回
) | ✅(但有
缺陷) | 有限(对对象不精确) |
| 所有类型(精确内部标签) | ✅ | ✅ | 最高(推荐) |
| 对象是否属于某个构造函数 | ✅(但依赖原型链) | ❌(不适用于原始类型) | 有限(跨框架问题) |
何时用哪个? |
- 需要精确类型(如区分 [object Array]和 [object Object]):用 Object.prototype.toString.call()。
- 检查原始类型(如 number、string):用 typeof(注意 null的坑)。
- 检查对象是否由某个构造函数创建(如自定义类实例):用 instanceof(但注意局限性)。
补充:为什么 typeof null === "object"?
这是 JavaScript 早期的设计错误,由于历史原因保留至今。要检测 null,需直接比较:
value === null
- 简单描述一下Typescript和Javascript的关系和区别。 答:Typescript主要是对JS的那个类型上面进行了扩展,因为JS它有很多隐性的类型转换,它不安全。然后Typescript会对于函数的返回跟传参有更严格的规定,还有结构就是数据结构也会有更加多的声明接口。就这么多。 标答: TS是JS的超集。它在 JavaScript 的基础上添加了静态类型检查,并且提供了更多现代化的功能,如接口、类、模块等。 3.2 核心区别:类型系统 3.2.1 JavaScript是动态类型,TypeScript是静态类型 3.2.2 类型注解 TypeScript 提供了类型注解,让我们明确指定变量、函数的类型。
let count: number = 10; // count被明确声明为number类型 let name: string = "Alice"; // name被明确声明为string类型
3.3.1 类与继承在 JavaScript 中,类和继承在 ES6 之前并不原生支持,直到 ES6 才引入了类的概念。即使有了类的支持,JavaScript 的类并不具备类型安全。TypeScript 支持访问控制符(public、private、protected)3.3.2 接口(Interface)接口 是 TypeScript 独有的。3.3.3 泛型类TypeScript 允许定义泛型类,增强代码复用性与类型安全。
3.4 编译与运行JavaScript 代码不需要编译,你可以直接在浏览器中运行,或者通过 Node.js 直接执行。而 TypeScript 需要先经过编译,转换为标准的 JavaScript 代码,才能执行。你需要使用 tsc 命令来将 TypeScript 代码编译成 JavaScript 代码,然后再执行生成的 JavaScript 文件。
3.5 TypeScript的优势主要体现在以下几点:
- 静态类型检查:TypeScript 提供了强大的类型系统,帮助我们在编译时就发现错误,而不是等到运行时才发现问题。
- 更好的开发体验:因为 TypeScript 强制了类型安全,所以 IDE 和编辑器能够提供更加智能的代码补全、自动提示和错误检查功能。这让开发变得更加高效。
- 面向对象编程支持:TypeScript 提供了更强大的面向对象编程功能,比如接口、类、继承、抽象类等,让代码结构更清晰,更容易扩展。
- 适合大型项目:在大型应用中,TypeScript 的类型检查和模块化功能能大大减少代码出错的概率,确保项目的可维护性。
- 有没有用过react?有没有用过python的前端模板库? 没有
- 说一说vue3和vue2的区别,或者说vue3最大的升级?
- 使用vue3的过程中你觉得最容易踩坑的地方?或者说你对不熟悉vue的人有什么建议和忠告?
- vue里有哪些通信的方案?
- 假设有很深的组件想要和最顶层组件通信,你有哪些方法?
- 你在使用python和vue时,有因为他俩的框架、作用、语言不一样而产生什么感触或者思考吗?舒服和不舒服的地方都可以。
- 你为什么从Flask改用Fastapi?你觉得最核心的区别是什么?你为什么觉得fastapi更轻,Flask更重?
- 你用过springboot和spring MVC,介绍一下,比如说springboot和spring MVC他们的区别是什么?
- 假设给你四个选项,fast API,然后flask,然后spring boot,spring MVC. 假设有一个项目让你去做这四个的选型,那你的思路和结论会是什么呢?
- 我看你有两个和人工智能算法相关的项目,深度学习脑电信号抑郁症检测系统和一个舆情监测系统,算法是你来写的吗?
- 两个项目其实你对具体代码不太清楚对吧?那基于这两个传统的机器学习算法去对比现在更火的“大模型”,你有什么对比或者思考吗?
- 你从大模型上学习到了什么吗?或者在你的学习或者在项目里有什么应用。 (我这个时候还不了解他说的大模型是什么,其实是指现有的万亿参数量的LLM模型,与普通的机器学习模型有什么区别?你有什么应用?)
- 大模型可能应用在NLP,那你觉得大模型还能运用在其他哪些场景?
- 你觉得AI书写代码(vibe coding)会有带来一些劣势或者弊端吗?
- 回想一下你做的几个项目,你觉得遇到过的最有意思或最挑战的事情是什么?
- 技术上你觉得有哪些挑战的东西吗?
- 校园导航小程序,就是这个项目里有在技术上遇到什么问题,然后你是怎么解决的?
- 小程序里边的那些地点都是怎么来的?
- 你们一个个走过去记录的是吧?对你觉得这个有更高效的办法吗?
- 你接了腾讯地图的组件,为什么不用这个组件自己的导航服务呢?
算法考试
数组展平
写一个数组 flatten 方法,将多维数组打平为一维数组。
题目描述
[1, [2, 3], [[4], 5]]=> [1, 2, 3, 4, 5]
["1", [{ a: 2 }, 3], [[4], 5]]=> ["1", { a: 2 }, 3, 4, 5]
初级JS特性实现(使用基本的循环和条件判断)
在初级JS实现中,我们主要使用以下技术:
for循环Array.isArray()方法concat()方法- 递归
function flattenArray(arr) {
var flattened = []; // 初始化一个空数组来存储扁平化后的元素
for (var i = 0; i < arr.length; i++) { // 遍历数组中的每一个元素
if (Array.isArray(arr[i])) { // 判断当前元素是否为数组
// 如果是数组,递归调用flattenArray,并将结果与flattened连接
flattened = flattened.concat(flattenArray(arr[i]));
} else {
// 如果不是数组,直接添加到flattened中
flattened.push(arr[i]);
}
}
return flattened; // 返回最终的扁平化数组
}
// 测试
console.log(flattenArray([1, [2, 3], [[4], 5]])); // 输出: [1, 2, 3, 4, 5]
中等JS特性实现(使用高阶函数和箭头函数)
在中等JS实现中,我们将使用以下技术:
Array.prototype.reduce()方法Array.prototype.concat()方法- 箭头函数
() => {} - 递归
const flattenArray = (arr) => {
return arr.reduce((acc, current) => {
return acc.concat(Array.isArray(current) ? flattenArray(current) : current);
}, []);
};
// 测试
console.log(flattenArray([1, [2, 3], [[4], 5]])); // 输出: [1, 2, 3, 4, 5]
代码解释
- 箭头函数定义使用 ES6 箭头函数语法定义 flattenArray函数,使其更加简洁。
- 使用 reduce方法调用 reduce方法遍历数组 arr。reduce方法接受两个参数:回调函数和初始值。回调函数接收两个参数:acc(累加器):上一次迭代的结果。current(当前元素):当前正在处理的数组元素。初始值为空数组 []。
- 累加器逻辑对于每一个 current元素:使用三元运算符 ? :判断 current是否为数组:如果是数组,则递归调用 flattenArray(current)进行扁平化,并将结果与 acc连接。如果不是数组,则直接将 current添加到 acc中。
- 初始值提供一个初始的空数组 []给 reduce方法,确保第一次调用回调函数时 acc是一个数组。
- 返回结果reduce方法最终会返回一个完全扁平化的一维数组。
list转为forest
✅ 题目描述:
给定一个包含 id和 parentId字段的 节点列表(Node List),其中:
- 每个节点是一个对象,至少包含
id和name字段; - 部分节点可能包含一个可选的
parentId字段,用来表示该节点的父节点; - 如果一个节点 没有
parentId字段,则说明它是 根节点; - 目标是将这个 扁平的节点列表,按照 父子关系 转换成一个 TreeNode 的森林(即多个树的集合,TreeNode[]),其中树的层级关系通过
children字段来表达。
📦 接口定义(TypeScript 风格,但你可以用 JS 实现逻辑):
interface Node {
id: number;
name: string;
parentId?: number; // 可选,如果存在,则表示其父节点的 id
}
interface TreeNode {
id: number;
name: string;
children?: TreeNode[]; // 可选,子节点数组
}
🛠️ 需要实现的方法:
function listToForest(list: Node[]): TreeNode[] {
// your code here
}
🧪 示例输入:
const list = [
{ id: 1, name: '1' },
{ id: 2, name: '2' },
{ id: 3, parentId: 1, name: '1.3' },
{ id: 4, parentId: 1, name: '1.4' },
{ id: 5, parentId: 3, name: '1.3.5' },
];
✅ 示例输出:
const result = [
{
id: 1,
name: '1',
children: [
{
id: 3,
name: '1.3',
children: [
{
id: 5,
name: '1.3.5',
},
],
},
{
id: 4,
name: '1.4',
},
],
},
{
id: 2,
name: '2',
},
];
🔍 解题思路(简要说明):
要将一维的 Node 列表转换为具有层级结构的 TreeNode 森林,可以按如下步骤进行:
- 建立映射表:用一个 Map 或对象,以 id为键,存储对应的 TreeNode,方便快速查找。
- 区分根节点和子节点:遍历所有节点,如果节点 没有 parentId,则它是 根节点;如果有 parentId,则它是某个父节点的 子节点。
- 构建树结构:先将所有节点都先转成 TreeNode(不带 children)并放入 Map 中;再遍历所有节点,对于有 parentId 的节点,找到其父节点,并将当前节点添加到父节点的 children数组中;最后,收集所有 没有 parentId 的节点(即根节点),它们组成最终的 Forest(树数组)。
🧠 JavaScript 版本的实现代码:
function listToForest(list) {
const nodeMap = new Map(); // id -> TreeNode
const forest = []; // 最终的森林(根节点数组)
const allNodes = []; // 所有转换后的 TreeNode(不含children关系)
// 第一步:将所有节点转换为 TreeNode,并存入 nodeMap 和 allNodes
for (const node of list) {
const treeNode = { id: node.id, name: node.name };
nodeMap.set(node.id, treeNode);
allNodes.push(treeNode);
}
// 第二步:构建父子关系
for (const node of list) {
const treeNode = nodeMap.get(node.id);
if (node.parentId !== undefined) {
const parentNode = nodeMap.get(node.parentId);
if (parentNode) {
if (!parentNode.children) {
parentNode.children = [];
}
parentNode.children.push(treeNode);
}
} else {
// 没有 parentId,是根节点
forest.push(treeNode);
}
}
return forest;
}
二叉树所有根到叶子路径组成的数字之和
![[attachments/Pasted image 20251026184555.png]]
function sumNumbers(root) {
if (!root) return 0;
let totalSum = 0;
function dfs(node, currentSum) {
// 计算当前路径的数字
const newSum = currentSum * 10 + node.val;
// 如果是叶子节点,将当前数字加到总和中
if (!node.left && !node.right) {
totalSum += newSum;
return;
}
// 递归处理左右子树
if (node.left) dfs(node.left, newSum);
if (node.right) dfs(node.right, newSum);
}
dfs(root, 0);
return totalSum;
}
反问环节
- 我能看出来我对算法这块还不熟练,你可以对我有什么更好的建议,让我以后去进步吗? 我觉得可能要挑一个你未来想要做的方向,然后在这个方向上可能多深入一些。我们都说其实比如说在学校里可能是有可能是广度,但是只有广度可能是不够的。然后你可能需要在几个方向去做深入一些。比如说这些算法,你之前提到你可能做过一些算法的工作,但可能这些算法答的也不是特别好,那是不是算法再看看。对,那前端你说做的比较多对吧?那其实可能有一些细节,前端领域挺多知识可能你后边可以去多了解,就可能每个方向都挑几个你重点关心的,再深入这种工作。
