前端八股文面经大全:字节跳动交易与广告前端一面(2026-2-10)·面经深度解析

前端八股文面经大全:字节跳动交易与广告前端一面(2026-2-10)·面经深度解析

前言

大家好,我是木斯佳。

在这个春节假期,当大家都在谈论返乡、团圆与休息时,作为一名技术人,我的思考却不由自主地转向了行业的「冬」与「春」。

相信很多人都感受到了,在AI浪潮的席卷之下,前端领域的门槛在变高,纯粹的“增删改查”岗位正在肉眼可见地减少。曾经热闹非凡的面经分享,如今也沉寂了许多。但我们都知道,市场的潮水退去,留下的才是真正在踏实准备、努力沉淀的人。学习的需求,从未消失,只是变得更加务实和深入。

正值春节,也是复盘与规划的好时机。结合ZEEKLOG这次「春节代码贺新年」活动所提倡的“用技术视角记录春节、复盘成长”,我决定在这个假期持续更新专栏,帮助年后参加春招的同学。

这个专栏的初衷很简单:拒绝过时的、流水线式的PDF引流贴,专注于收集和整理当下最新、最真实的前端面试资料。我会在每一份面经和八股文的基础上,尝试从面试官的角度去拆解问题背后的逻辑,而不仅仅是提供一份静态的背诵答案。无论你是校招还是社招,目标是中大厂还是新兴团队,只要是真实发生、有价值的面试经历,我都会在这个专栏里为你沉淀下来。

温馨提示:市面上的面经鱼龙混杂,甄别真伪、把握时效,是我们对抗内卷最有效的武器。

在这个假期,让我们一起充电,为下一个技术春天做好准备。

在这里插入图片描述

面经原文内容

📍面试公司:字节跳动

🕐面试时间:近期,用户上传于02-10

💻面试岗位:前端 - 中国交易与广告职位

👥面试形式:双面试官(一个主面,一个闭麦旁听)

⏱️面试时长:1小时

❓面试问题:

开场

  • 自我介绍
  • 实习经历拷打

CSS/浏览器

  • 图片懒加载实现(IntersectionObserver)
  • 考虑过兼容性吗?
  • 原生兼容老浏览器怎么实现图片懒加载?(没答出来)
  • 多行溢出怎么实现(display: -webkit-box)
  • 单行溢出怎么实现
  • 考虑过兼容性吗?多行溢出有其他方法实现吗?

JS核心

  • 跨域知道吗?
  • 能说一下闭包吗?(提到了防抖节流)
  • 防抖节流的应用场景
  • input搜索防抖,但万一第一次请求比第二次慢怎么办?(没答出来)
  • 节流的应用场景(鼠标频繁触发)
  • 事件冒泡和捕获
  • 事件委托

工程化

  • git merge和git rebase的区别

网络

  • 为什么要设置跨域?(域名、端口号、协议)
  • 遇到跨域问题,除了配置代理还能怎么办?

框架(Vue/React)

  • Vue多还是React多?(答Vue)
  • 知道hooks吗?(React hooks)
  • hooks在React什么地方都能使用吗?(答得不好,转问Vue)
  • Vue2和Vue3的响应式区别
  • 虚拟DOM diff算法中为什么key不能用index实现

来源:牛客网 smile丶snow

📝 字节跳动交易与广告前端一面·面经深度解析

🎯 面试整体画像

维度特征
部门定位字节跳动 - 中国交易与广告(核心变现业务)
面试风格基础纵深 + 场景追问 + 兼容性敏感
难度评级⭐⭐⭐⭐(四星,考察全面且深入)
考察重心浏览器原理、JS核心、工程化、框架原理

🖼️ 图片懒加载

问题:图片懒加载实现(IntersectionObserver)

// IntersectionObserver实现functionlazyLoadImages(){const images = document.querySelectorAll('img[data-src]')const observer =newIntersectionObserver((entries)=>{ entries.forEach(entry=>{if(entry.isIntersecting){const img = entry.target img.src = img.dataset.src img.removeAttribute('data-src') observer.unobserve(img)}})},{root:null,rootMargin:'0px',threshold:0.1}) images.forEach(img=> observer.observe(img))}

问题:原生兼容老浏览器怎么实现?

// 降级方案:scroll事件 + getBoundingClientRectfunctionlazyLoadCompat(){const images = document.querySelectorAll('img[data-src]')functionloadImages(){ images.forEach(img=>{const rect = img.getBoundingClientRect()const isVisible = rect.top < window.innerHeight && rect.bottom >0if(isVisible && img.dataset.src){ img.src = img.dataset.src img.removeAttribute('data-src')}})}// 初始加载loadImages()// 滚动监听(节流优化)let ticking =false window.addEventListener('scroll',()=>{if(!ticking){requestAnimationFrame(()=>{loadImages() ticking =false}) ticking =true}})// resize也要检查 window.addEventListener('resize', loadImages)}

问题:考虑过兼容性吗?

// 完整兼容方案if('IntersectionObserver'in window){// 使用IntersectionObserverlazyLoadImages()}else{// 使用scroll降级方案lazyLoadCompat()}

📝 文本溢出

问题:单行溢出怎么实现

.single-line{overflow: hidden;white-space: nowrap;text-overflow: ellipsis;}

问题:多行溢出怎么实现

/* WebKit私有属性 */.multi-line{display: -webkit-box;-webkit-line-clamp: 3;/* 显示3行 */-webkit-box-orient: vertical;overflow: hidden;}

问题:多行溢出有其他方法吗?

/* 方案1:伪元素模拟 */.multi-line-fallback{position: relative;line-height: 1.5em;max-height: 4.5em;/* 3行 * 1.5em */overflow: hidden;}.multi-line-fallback::after{content:"...";position: absolute;bottom: 0;right: 0;background: white;padding-left: 0.2em;}
// 方案2:JS动态计算functiontruncateText(selector, lines){const el = document.querySelector(selector)const lineHeight =parseInt(getComputedStyle(el).lineHeight)const maxHeight = lineHeight * lines if(el.scrollHeight > maxHeight){// 二分查找截断位置let low =0, high = el.textContent.length while(low < high){const mid = Math.floor((low + high)/2) el.textContent = el.textContent.slice(0, mid)+'...'if(el.scrollHeight > maxHeight){ high = mid }else{ low = mid +1}} el.textContent = el.textContent.slice(0, low -1)+'...'}}

🔒 闭包与防抖节流

问题:说一下闭包

// 闭包:函数 + 词法环境的引用functioncreateCounter(){let count =0// 被内部函数引用returnfunction(){ count++return count }}const counter =createCounter() console.log(counter())// 1 console.log(counter())// 2// count变量没有被销毁,形成闭包

问题:防抖节流的应用

// 防抖:只执行最后一次functiondebounce(fn, delay){let timer returnfunction(...args){clearTimeout(timer) timer =setTimeout(()=>fn.apply(this, args), delay)}}// 应用:搜索输入、窗口resize、自动保存// 节流:控制执行频率functionthrottle(fn, interval){let last =0returnfunction(...args){const now = Date.now()if(now - last >= interval){fn.apply(this, args) last = now }}}// 应用:滚动加载、鼠标移动、拖拽

问题:input搜索,第一次请求比第二次慢怎么办?

// 问题场景:// 输入"ab" → 请求1 (查"ab") 延迟3秒// 输入"abc" → 请求2 (查"abc") 延迟1秒// 请求2先返回,显示"abc"// 请求1后返回,覆盖显示"ab" ❌// 解决方案1:AbortController取消旧请求functioncreateSearch(){let currentController =nullreturnasync(keyword)=>{// 取消上一次请求if(currentController){ currentController.abort()} currentController =newAbortController()try{const response =awaitfetch(`/api/search?q=${keyword}`,{signal: currentController.signal })const data =await response.json()renderResults(data)}catch(err){if(err.name ==='AbortError'){ console.log('请求被取消')}}}}// 解决方案2:请求序列号(忽略过期请求)functioncreateSearchWithSeq(){let lastRequestId =0returnasync(keyword)=>{const requestId =++lastRequestId const data =awaitfetch(`/api/search?q=${keyword}`).then(r=> r.json())// 只处理最新的请求if(requestId === lastRequestId){renderResults(data)}}}

🔄 事件机制

问题:事件冒泡和捕获

<divid="parent"><buttonid="child">点击</button></div><script>// 捕获阶段:window → document → html → body → ... → 目标元素// 冒泡阶段:目标元素 → ... → body → html → document → window document.getElementById('parent').addEventListener('click',()=>{ console.log('parent 捕获')},true)// true = 捕获阶段 document.getElementById('parent').addEventListener('click',()=>{ console.log('parent 冒泡')},false)// false = 冒泡阶段 document.getElementById('child').addEventListener('click',()=>{ console.log('child 冒泡')},false)// 点击输出顺序:// parent 捕获// child 冒泡// parent 冒泡</script>

问题:事件委托

// 利用冒泡,父元素统一处理子元素事件 document.querySelector('ul').addEventListener('click',(e)=>{const target = e.target if(target.tagName ==='LI'){ console.log('点击了', target.textContent)// 处理逻辑...}})// 优点:// 1. 减少事件监听器数量(从N个变成1个)// 2. 动态添加的元素也能被处理

🔧 Git操作

问题:git merge和git rebase的区别

维度git mergegit rebase
提交历史保留分支合并历史,有merge commit线性历史,无merge commit
可读性真实反映实际开发流程更清晰简洁
冲突处理一次处理每个commit都可能处理冲突
安全性安全,不会改写历史危险,会改写历史
# git mergegit checkout main git merge feature # 结果:main ← feature 有合并节点# git rebase(个人分支用)git checkout feature git rebase main # 将feature的提交"移动"到main之后git checkout main git merge feature # 快进合并,得到线性历史

使用原则

  • 公共分支(main/develop):用merge
  • 个人分支(feature):用rebase整理后合并

🌐 跨域

问题:为什么要设置跨域?

同源策略:协议、域名、端口三者相同

// 同源示例https://example.com/page1 和 https://example.com/page2 ✅ // 不同源示例http://example.com 和 https://example.com ❌ 协议不同 example.com 和 api.example.com ❌ 域名不同 example.com:8080 和 example.com:3000 ❌ 端口不同 

作用

  1. 防止恶意网站读取另一个网站的敏感数据
  2. 限制恶意请求(CSRF防护)
  3. 隔离不同来源的内容

问题:除了配置代理还能怎么办?

// 1. CORS(后端配置)// 后端设置响应头 res.setHeader('Access-Control-Allow-Origin','https://example.com') res.setHeader('Access-Control-Allow-Methods','GET, POST, PUT') res.setHeader('Access-Control-Allow-Headers','Content-Type') res.setHeader('Access-Control-Allow-Credentials','true')// 2. JSONP(只支持GET)functionjsonp(url, callback){const script = document.createElement('script')const callbackName ='jsonp_cb_'+ Date.now() window[callbackName]=(data)=>{callback(data)delete window[callbackName] document.body.removeChild(script)} script.src =`${url}?callback=${callbackName}` document.body.appendChild(script)}// 3. Nginx反向代理// nginx配置 location /api/{ proxy_pass http://backend-server/; proxy_set_header Host $host;}// 4. WebSocket(不受同源策略限制)const ws =newWebSocket('wss://api.example.com')// 5. postMessage(跨域窗口通信)// 父页面 iframe.contentWindow.postMessage(data,'https://child.com')// 子页面 window.addEventListener('message',(e)=>{if(e.origin ==='https://parent.com'){ console.log(e.data)}})

⚛️ React Hooks

问题:知道hooks吗?

// 常用Hooksconst[state, setState]=useState(initialState)// 状态useEffect(()=>{// 副作用// 执行return()=>{/* 清理 */}},[dependencies])const context =useContext(Context)// 上下文const[state, dispatch]=useReducer(reducer, init)// 复杂状态const memoizedFn =useCallback(fn, deps)// 缓存函数const memoizedValue =useMemo(()=>compute(a, b),[a, b])// 缓存值const ref =useRef(initialValue)// 引用

问题:hooks在React什么地方都能使用吗?

// ✅ 可以在函数组件中使用functionComponent(){const[count, setCount]=useState(0)return<div>{count}</div>}// ✅ 可以在自定义Hook中使用functionuseCustomHook(){const[value, setValue]=useState(0)return[value, setValue]}// ❌ 不能在class组件中使用classComponentextendsReact.Component{render(){const[count, setCount]=useState(0)// 错误!}}// ❌ 不能在普通函数中使用functionnormalFunction(){const[count, setCount]=useState(0)// 错误!}// ❌ 不能在条件语句中使用functionComponent(){if(condition){const[count, setCount]=useState(0)// 错误!}}// ❌ 不能在循环中使用functionComponent(){for(let i =0; i <10; i++){const[count, setCount]=useState(0)// 错误!}}

Hooks规则

  1. 只能在函数组件或自定义Hook的顶层调用
  2. 不能在条件、循环、嵌套函数中调用
  3. 必须保证每次渲染时调用顺序一致

🔄 Vue2/3响应式

问题:Vue2和Vue3的响应式区别

// Vue2:Object.definePropertyfunctiondefineReactive(obj, key, val){ Object.defineProperty(obj, key,{get(){// 依赖收集return val },set(newVal){if(newVal === val)return val = newVal // 触发更新}})}// 缺点:// 1. 无法检测新增/删除属性(需用Vue.set/Vue.delete)// 2. 无法直接监听数组变化(需要重写数组方法)// 3. 需要递归遍历所有属性(性能开销)// Vue3:Proxyfunctionreactive(target){returnnewProxy(target,{get(target, key, receiver){// 依赖收集track(target, key)return Reflect.get(target, key, receiver)},set(target, key, value, receiver){const oldValue = target[key]const result = Reflect.set(target, key, value, receiver)if(oldValue !== value){// 触发更新trigger(target, key)}return result }})}// 优点:// 1. 可以监听新增/删除属性// 2. 可以监听数组索引和length变化// 3. 懒递归(访问时才递归)

🎯 虚拟DOM与key

问题:为什么key不能用index实现?

// 场景:列表渲染const list =['a','b','c']// ❌ 使用index作为key list.map((item, index)=><li key={index}>{item}</li>)// ✅ 使用唯一id作为key list.map(item=><li key={item.id}>{item.name}</li>)

问题演示

// 初始列表:['a', 'b', 'c']// key: 0 1 2// 在开头插入'x'// 新列表:['x', 'a', 'b', 'c']// key: 0 1 2 3// diff过程:// key0: a → x (内容变化,需要更新)// key1: b → a (内容变化,需要更新)// key2: c → b (内容变化,需要更新)// key3: 新增c// 本应只插入一个节点,却导致后面所有节点都更新// 性能下降,且可能导致状态错误(输入框内容错位)

正确做法

// 使用唯一标识<li key={item.id}>{item.name}</li>// 如果没有id,可以使用复合标识<li key={`${item.type}-${item.index}`}>{item.name}</li>

可以用index的例外情况

  • 列表是静态的,不会增删改
  • 列表永远不会重新排序
  • 数据量很小,性能影响可接受

📚 知识点速查表

知识点核心要点
图片懒加载IntersectionObserver + scroll降级 + 节流优化
文本溢出单行(white-space) + 多行(-webkit-box) + JS降级
闭包函数+词法环境引用、内存泄漏注意
防抖节流防抖(最后一次) + 节流(频率控制) + AbortController
事件机制捕获(→) + 目标 + 冒泡(←) + 委托
Gitmerge(保留历史) + rebase(线性历史)
跨域同源策略 + CORS/JSONP/代理/WebSocket
Hooks顶层调用 + 顺序一致 + 自定义Hook
响应式defineProperty(全量) vs Proxy(懒递归)
key唯一稳定 + 避免index

📌 最后一句:

字节跳动的面试,是一场基础扎实度 + 场景应变力的双重检验。
每一个问题都在追问“如果xxx怎么办”,
他们要的不是背答案的人,
而是能应对各种边界情况的人

Read more

VSCode Github Copilot使用OpenAI兼容的自定义模型方法

VSCode Github Copilot使用OpenAI兼容的自定义模型方法

背景 VSCode 1.105.0发布了,但是用户最期待的Copilot功能却没更新!!! (Github Copilot Chat 中使用OpenAI兼容的自定义模型。) 🔥官方也关闭了Issue,并且做了回复,并表示未来也不会更新这个功能: “实际上,这个功能在可预见的未来只面向内部人员开放,作为一种“高级”实验功能。是否实现特定模型提供者的功能,我们交由扩展作者自行决定。仅限内部人员使用可以让我们快速推进,并提供一种可能并非始终百分之百完善,但能够持续改进并快速修复 bug 的体验。如果这个功能对你很重要,我建议切换到内部版本 insider。” 🤗 官方解决方案:安装VSCode扩展支持 你们完全不用担心只需要在 VS Code 中安装扩展:OAI Compatible Provider for Copilot 通过任何兼容 OpenAI 的提供商驱动的 GitHub Copilot Chat,使用前沿开源大模型,如 Kimi K2、DeepSeek

从 Copilot 到工程化 Agent 执行框架:基于OpenCode + OpenSpec 的企业级 AI Coding 落地实践

从 Copilot 到工程化 Agent 执行框架:基于OpenCode + OpenSpec 的企业级 AI Coding 落地实践

引言:AI Coding 进入规范驱动自动化时代         当前,许多开发者在使用 AI 编程助手时正普遍面临—个痛点:在处理大型项目时, AI 似乎会“遗忘”上下文,导致代码回归、引入新 Bug 或生成不符合项目规范的混乱代码。正如研发同学反复出现的挫败感:  “代码库越大, AI 弄得越乱”。         这种被称为“Vibe Coding”的模式,是 AI 辅助工程必要的、但也是原始的第—步。它更像—种不可预测的艺术,而非可重复、可扩展的科学。要真正释放 AI 的生产力,我们必须迎来—次范式的进化:从凭感觉的“Vibe Coding” ,转向由规范驱动的(Spec-Driven Development)专业化 AI 工程新范式。         本文将深入探讨如何将强大的

Midjourney官网地址是哪个?有没有中文官网?

Midjourney官网地址是哪个?有没有中文官网?

作为AI绘画领域的明星工具,Midjourney凭借其强大的图像生成能力风靡全球。许多用户初次接触时,最常问的问题便是:Midjourney的官网地址是什么?是否有中文官网? 一、Midjourney官网入口 Midjourney的唯一官方访问地址为: 👉 https://www.midjourney.com         需要注意的是,Midjourney的核心服务基于Discord平台运行。用户需先注册Discord账号,通过官网引导加入Midjourney频道,重要的是中文用户需要魔法才能使用官方MJ绘画功能。官网主要提供功能说明、订阅计划、作品展示等基础信息。 二、中文用户如何快速上手?         目前Midjourney尚未推出中文官网,且操作界面以英文为主。对于不熟悉Discord或英文界面的用户,可通过以下方式降低使用门槛: 1. 浏览器翻译插件(如谷歌翻译)辅助阅读 2. 参考中文社区教程(知乎、B站等平台有大量指南) 3. 使用第三方API服务——例如 OpenXS Midjourney API,提供全中文文档和本地化技术支

RTX 4070本地部署Stable Diffusion保姆级教程:从环境搭建到4K写实人像实战

RTX 4070本地部署Stable Diffusion保姆级教程:从环境搭建到4K写实人像实战

前言 最近换了一台 RTX 4070 (8G显存) 的笔记本,想着算力不能浪费,就折腾了一下本地部署 AI 绘画(Stable Diffusion)。 网上很多教程要么太老,要么就是让你装 Python、配 Git,环境报错能劝退 90% 的人。其实现在早就有“一键启动”的整合包了。 这篇文章不讲虚的理论,只记录我跑通的这套最稳的工作流。如果你也是 N 卡用户(推荐 3060 以上),照着做,半小时内就能画出超写实的 4K 美女图。 上效果 为了方便大家,我把文中用到的“启动器整合包”和“核心模型”都打包好了,链接放在文末,需要的自取。 一、 准备工作 1. 硬件要求 * 显卡: 最好是