热乎美团前端面经

  1. js 中 this指向问题:
var a = 1; 
var b = { c: function ()
 { console.log(this.a); }, 
d: () => { console.log(this.a); } };
 b.d.bind({ a: 2 }); 
var fun = b.c; 
fun(); 
b.c(); 
b.d(); 

第一个func应该是隐式类型绑定,this指向window,
window.func() =>1
第三个箭头函数本身不含有this,绑定的是定义时候的上下文,=> 1;
第二个显式绑定,this指向b,b没有a属性打印undefined
2. 事件轮询机制:

console.log(1) 
setTimeout(() => {
 console.log(2) 
Promise.resolve().then(() => {
console.log(3) }) })
 new Promise((resolve) => { 
console.log(4) 
setTimeout(() => { 
console.log(5) resolve(); }, 2);
 }).then(res => { 
console.log(res) }); 

// 1 4 2 3 5 undefined
3. 手写promsie.all

function all(promises){ 
const values = []; 
return new Promise((resolve, reject)=>
 { promises.forEach(
(promise, index)=> 
{ promise.then((value)=>{ 
//values.push(value); 
values[index] = value; 
if(values.length == promises.length){ 
resolve(values); } },
 reason => { reject(reason); })
 })
 }) 
3.// 环形链表判断:
  1. 说了快慢指针
    // 对象是否有循环引用
    // 没搞清楚这个题目:
//line=readline() 
//print(line) 
var a = { b: { c: { d: a } } } 
function refCycle(obj){ 
for(let key in obj){ 
if(obj[key] == obj){ 
return true; } else{ 
refCycle(obj[key]); } 
} } 
console.log(refCycle(a)) 
function fn(object) {
// 首先判断 object 是否存在于 map.keys 中 
if (Array.from(map.keys()).includes(object)) 
{ // 如果存在则取出值并返回 return map.get(object); } 
var cloneObj = {}; 
// 设置 object 为 key,cloneObj 为值 
map.set(object, cloneObj); 
for (var key in object) { 
// 赋予新对象相应的 property 
// 通过递归调用来拷贝 property 的值
 cloneObj[key] = fn(object[key]); 
} 
// 返回新对象 return cloneObj;
 } 
var obj = {}; 
obj.a = obj; 
var map = new Map(); 
fn(obj); 

博客地址: https://blog.csdn.net/weixin_33738982/article/details/91414115?ops_request_misc=%25257B%252522request%25255Fid%252522%25253A%252522160920791616780271113414%252522%25252C%252522scm%252522%25253A%25252220140713.130102334…%252522%25257D&request_id=160920791616780271113414&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2allsobaiduend~default-1-91414115.nonecase&utm_term=%E5%AF%B9%E8%B1%A1%E5%BE%AA%E7%8E%AF%E5%BC%95%E7%94%A8

  1. 手写一个flat函数
    刚开始写了一个版本:
Array.prototype.flat1 = 
function (arr, n){ 
let newArr = new Array(); 
for(let i = 0; i < arr.length; i++)( 
if(typeof(arr[i]) !== "object" && n-- > 0){
 newArr = newArr.concat(this.flat1(arr[i]));
 } else { 
newArr.push(arr[i]); } ) 
return newArr;
 }
 var flat = function(arr, depth){ 
let res = [], depthArg = depth || 1,
 depthNum = 1, 
flatMap = (arr) => { 
arr.map((element, index, array) => 
{ if(Object.prototype.toString(element).slice(8,-1) === "Array") 
{ if(depthNum < depthArg) {
 depthNum++; 
flatMap(element); } else 
{ res.push(element); 
if(index === array.length - 1) 
depthNum = 0; } } }) }; 
flatMap(arr); return res; }; 
let arr = [[1], [[2]], [3]]; 
console.log(flat(arr)); 
// [1,[2], [3]]
5.hash模式和history模式的实现原理
  1. 监听hash的改变:
<!DOCTYPE html> <html lang="en">
 <head> <meta charset="UTF-8"> 
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title>
 </head> <body> <div id="app"> 
<a href="#/home">首页</a> 
<a href="#/about">关于</a> 
</div> <div class="router-view">
</div> <script> 
// 获取router-view的dom const routerViewEl =
 document.getElementsByClassName("router-view")[0];
 // 监听url的改变 window.addEventListener("hashchange", () => 
{ switch (location.hash) { 
case "#/home": 
routerViewEl.innerHTML = "首页";
 break; 
case "#/about": routerViewEl.innerHTML = "关于";
 break; 
default: routerViewEl.innerHTML = ""; } }); // html5 中的history // history接口是HTML5新增加的,它有六种模式改变url而不刷新页面 // replaceState: 替换原来的路径 // pushState: 使用新的路径 // popState: 路径的回退 // go: 向前或向后 forward: 向 1. 获取router-view的dom 
const routerViewEl = 
document.getElementsByClassName("router-view")[0]; 
2.histort新增加api
// 获取所有的a元素,自己来监听a元素的改变 
const aEls = document.getElementsByTagName("a"); 
for (let el of aEls) 
{ el.addEventListener("click", 
e => { e.preventDefault(); 
const href = el.getAttribute("href");
 history.pushState({}, "", href); 
urlChange(); // history.go(-1) 
// history.back(); 
// urlChange(); }) } 
// 执行返回操作时候,依然来到urlChange
 window.addEventListener('popstate', urlChange);
 // window.addEventListener("go", urlChange);
 // window.addEventListener("pushState", urlChange); 
// 监听URL的改变 function urlChange() { 
console.log(location.pathname);
 switch (location.pathname) {
 case "/home": routerViewEl.innerHTML = "首页";
 break; 
case "/about": 
routerViewEl.innerHTML = "关于"; 
break; 
default: routerViewEl.innerHTML = ""; 
} };
  1. 实现数组的slice方法:
Array.prototype.slice = 
function(start, end){ 
let len = this.length; 
let l = start === undefined ? 0 : 
start < 0 ? Math.max(start + len, 0) : 
Math.min(start, len);
 let r = end === undefined ? len : end < 0 ?
 Math.max(end + len, 0) : 
Math.min(end, len); 
const res = []; while(l < r) 
{ res.push(this[l++]);
 } 
return res; }
  1. 判断数据类型3种方法,实现instaneOf
const instance_of = (left, rigth) =>
 { const baseType = ['number', 'string', 'boolean', 'undefined', 'symbol'];
 const RP = right.prototype; 
while(true){ if(left == null) { 
return false; } else if 
(left == RP) { return true; } 
left = left.__proto__; 
} }
#美团##校招##前端工程师##面经#
全部评论
楼主收到二面通知了吗
点赞 回复 分享
发布于 2021-01-12 11:37
第二个显示绑定??
点赞 回复 分享
发布于 2021-01-11 00:23
第一题我打印出来全是undefined
点赞 回复 分享
发布于 2021-01-09 22:14
请问楼主是在官网上投的么?还是内推呀?感觉现在美团没很多实习岗放出来
点赞 回复 分享
发布于 2020-12-31 14:03
实习?校招?社招?啥部门兄弟
点赞 回复 分享
发布于 2020-12-29 15:58
啥时候开始的呀,楼主
点赞 回复 分享
发布于 2020-12-29 15:32
这个面经。。。。
点赞 回复 分享
发布于 2020-12-29 12:51

相关推荐

让ai总结了一下问题和回答,心累了,面试官一直问优化相关的问题,多少也回答了一些出来,最后反问的时候,问有什么能加强的,说是觉得项目没什么亮点,一、代码问题的主动发现与预防主动发现方式静态代码分析:使用&nbsp;ESLint、TSLint&nbsp;等工具在编码阶段检测语法错误、代码规范问题、潜在逻辑漏洞(如未处理的空值、死循环)。自动化测试:通过单元测试(Jest)、集成测试(Cypress)覆盖核心逻辑,结合&nbsp;CI/CD&nbsp;流程在提交&nbsp;/&nbsp;部署前触发测试,提前暴露问题。代码审查:制定&nbsp;Code&nbsp;Review&nbsp;规范,重点检查边界条件、性能风险、安全性(如&nbsp;XSS、CSRF)。监控告警:线上通过&nbsp;Sentry&nbsp;等工具捕获运行时错误(如&nbsp;TypeError、Promise&nbsp;未捕获异常),结合日志分析高频异常点。预防措施制定开发规范:明确命名规则、代码结构、错误处理方式(如统一使用&nbsp;try/catch&nbsp;或全局异常捕获)。技术选型管控:避免引入低维护性依赖,优先选择成熟库并控制版本。定期重构:针对耦合度高、可维护性差的代码进行重构,降低后续迭代风险。二、To&nbsp;C&nbsp;项目的监控设计To&nbsp;C&nbsp;项目需重点关注用户体验与稳定性,监控设计可从以下层面展开:前端性能监控核心指标:首屏加载时间(FCP)、交互响应时间(TTI)、白屏时间,通过&nbsp;Performance&nbsp;API&nbsp;或第三方工具(如&nbsp;Lighthouse、阿里云&nbsp;ARMS)采集。资源加载:监控&nbsp;JS/CSS&nbsp;加载耗时、图片加载失败率,设置阈值告警(如某资源加载超时&nbsp;&gt;3s)。用户行为与异常监控错误监控:捕获&nbsp;JS&nbsp;运行时错误、接口错误(4xx/5xx)、资源加载失败,关联用户&nbsp;ID、设备信息便于定位。行为轨迹:记录用户点击、滑动等操作,分析卡顿、崩溃场景的触发路径(如某按钮点击后高频报错)。业务指标监控核心流程转化:如注册、支付步骤的成功率,异常中断时触发告警。设备兼容性:统计不同浏览器&nbsp;/&nbsp;机型的报错率,优先修复高占比问题。实现方式埋点系统:通过&nbsp;SDK&nbsp;主动上报监控数据,后端存储后用&nbsp;Grafana&nbsp;等工具可视化。实时告警:配置短信&nbsp;/&nbsp;钉钉通知,针对严重错误(如大面积白屏、支付失败)即时响应。三、虚拟列表优化实现虚拟列表核心是只渲染可视区域内的&nbsp;DOM&nbsp;元素,减少渲染压力,实现思路:核心原理计算可视区域高度、单个&nbsp;item&nbsp;高度,确定可见项数量(如可视区高度&nbsp;500px,item&nbsp;高&nbsp;50px&nbsp;→&nbsp;可见&nbsp;10&nbsp;项)。监听滚动事件,动态计算滚动偏移量,确定当前需渲染的&nbsp;item&nbsp;起始索引。通过容器内的&nbsp;“占位元素”&nbsp;撑起列表总高度,避免滚动条异常,可视区项通过绝对定位展示。关键优化缓存已渲染项:避免滚动时频繁销毁&nbsp;/&nbsp;创建&nbsp;DOM,仅更新位置和内容。预渲染缓冲区:在可视区上下额外渲染&nbsp;1-2&nbsp;项,减少快速滚动时的空白闪烁。动态高度支持:若&nbsp;item&nbsp;高度不固定,可通过预估高度&nbsp;+&nbsp;滚动时修正位置解决。库选型:优先使用成熟库(如&nbsp;react-virtualized、vue-virtual-scroller),减少自研成本。四、列表滑动卡顿的排查与优化排查方向性能分析:用&nbsp;Chrome&nbsp;DevTools&nbsp;的&nbsp;Performance&nbsp;面板录制滑动过程,查看是否有长任务(&gt;50ms)、频繁重排(Layout)/&nbsp;重绘(Paint)。DOM&nbsp;数量:检查列表是否渲染了过多&nbsp;DOM(如未做虚拟列表),导致渲染线程阻塞。事件处理:滑动时是否绑定了高频事件(如&nbsp;scroll、touchmove)且未做节流&nbsp;/&nbsp;防抖,导致&nbsp;JS&nbsp;线程繁忙。样式问题:是否使用复杂样式(如阴影、渐变)或强制同步布局(如频繁读取&nbsp;offsetHeight&nbsp;后修改样式)。优化措施实现虚拟列表:减少&nbsp;DOM&nbsp;数量(见上文)。优化事件:对&nbsp;scroll/touchmove&nbsp;事件节流(如&nbsp;100ms&nbsp;触发一次),避免高频执行。减少重排&nbsp;/&nbsp;重绘:将固定样式抽离为&nbsp;CSS&nbsp;类,避免&nbsp;inline&nbsp;样式;使用&nbsp;will-change:&nbsp;transform&nbsp;让浏览器单独分层渲染。数据处理:若滑动时需加载数据,提前预加载并缓存,避免同步阻塞。五、白屏的检测与解决检测方式前端埋点:在页面关键节点(如&nbsp;DOMContentLoaded、首屏元素渲染完成)设置时间戳,若超过阈值(如&nbsp;5s&nbsp;未渲染)则上报白屏事件。图片监控:在页面顶部放一个&nbsp;1x1&nbsp;像素的&nbsp;“探针图片”,若加载成功则证明页面正常,否则判定为白屏。错误关联:结合&nbsp;JS&nbsp;错误日志(如关键脚本加载失败、语法错误)定位白屏原因。解决思路加载问题:优化资源加载(如&nbsp;CDN&nbsp;加速、代码分割、懒加载),处理脚本加载失败(如重试机制、备用&nbsp;CDN)。渲染阻塞:避免&nbsp;JS&nbsp;阻塞&nbsp;HTML&nbsp;解析(如用&nbsp;defer/async),减少首屏不必要的&nbsp;CSS/JS。数据依赖:若白屏因接口延迟,增加骨架屏、加载动画,避免用户感知空白;接口失败时显示错误提示并提供重试。兼容性:修复特定浏览器的渲染&nbsp;bug(如&nbsp;CSS&nbsp;前缀缺失、ES6+&nbsp;语法未转译)。六、ECharts&nbsp;性能问题及优化常见性能问题大数据量渲染卡顿(如万级以上数据点)。频繁更新(如实时数据)导致内存泄漏或&nbsp;CPU&nbsp;占用过高。图表容器大小频繁变化时重绘异常。折线图(多日期筛选)的优化与后端方案前端优化:数据采样:根据日期范围动态调整精度(如日级展示&nbsp;24&nbsp;点,周级展示&nbsp;24*7&nbsp;点,月级按天采样而非小时,避免数据量过大)。节流重绘:筛选日期时,通过防抖(如&nbsp;300ms&nbsp;延迟)避免频繁调用&nbsp;setOption。销毁旧实例:切换筛选条件前,调用&nbsp;dispose&nbsp;()&nbsp;销毁旧图表,释放内存。懒加载:非首屏图表延迟初始化,避免阻塞首屏渲染。与后端沟通方案:动态返回精度:后端根据筛选的时间范围(天&nbsp;/&nbsp;周&nbsp;/&nbsp;月)返回对应粒度的数据(如周级返回按小时聚合的平均值,而非每小时原始数据)。分页&nbsp;/&nbsp;分段加载:若需保留细粒度,后端支持按时间段分段返回,前端滚动时再加载后续数据。数据压缩:后端用二进制或精简格式(如仅返回&nbsp;[x,y]&nbsp;数组而非完整对象)减少传输量。ECharts&nbsp;适配方案响应式容器:监听窗口&nbsp;resize&nbsp;事件,调用&nbsp;resize&nbsp;()&nbsp;方法调整图表大小,结合&nbsp;CSS&nbsp;媒体查询适配不同屏幕。移动端优化:简化图表样式(如隐藏次要网格线、缩小字体),触摸交互适配(如支持双击放大、手势缩放)。七、图片优化方向资源优化格式选择:优先使用&nbsp;WebP/AVIF(比&nbsp;JPEG&nbsp;小&nbsp;30%+),降级兼容旧浏览器;简单图形用&nbsp;SVG&nbsp;替代位图。压缩处理:通过工具(如&nbsp;TinyPNG)或后端服务(如七牛云)压缩图片,平衡质量与体积。合理尺寸:根据展示容器大小提供多分辨率图片(如&nbsp;srcset&nbsp;属性),避免大图小用。加载优化懒加载:使用&nbsp;IntersectionObserver&nbsp;监听图片进入视口后再加载,减少首屏请求。预加载:对首屏或即将展示的图片(如轮播图下一张)用&nbsp;link&nbsp;[rel=&quot;preload&quot;]&nbsp;预加载。缓存策略:设置合理的&nbsp;Cache-Control&nbsp;头,复用缓存减少重复请求。体验优化占位符:加载前显示低分辨率缩略图或纯色占位,减少布局偏移(CLS)。错误处理:图片加载失败时显示默认图,避免破图影响体验。八、图片加载时间的检测前端检测监听事件:通过&nbsp;img.onload&nbsp;记录加载完成时间,减去&nbsp;img.src&nbsp;赋值时间,得到加载耗时。Performance&nbsp;API:使用&nbsp;performance.getEntriesByType&nbsp;('resource')&nbsp;获取图片资源的加载详情(如&nbsp;startTime、responseEnd),计算耗时&nbsp;=&nbsp;responseEnd&nbsp;-&nbsp;startTime。埋点上报:将检测到的耗时结合图片&nbsp;URL、用户设备信息上报,分析慢加载图片。工具辅助浏览器&nbsp;DevTools:Network&nbsp;面板筛选&nbsp;img&nbsp;类型资源,查看各阶段耗时(如&nbsp;DNS、TCP、下载)。第三方监控:通过&nbsp;Lighthouse&nbsp;或监控平台(如&nbsp;Datadog)批量分析页面图片加载性能。
查看8道真题和解析
点赞 评论 收藏
分享
评论
6
33
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务