令人窒息的百度面试题(正值换工作季,还不收藏???)

news/2024/11/22 20:02:27/

最近去网上找了一些百度的面经,冥冥之中在众多的面试题中打开了下边两个面试题:

2021百度前端社招面经

百度前端面试题分享,带答案

看完之后我直呼“哇哦~”,全部在我的射程范围之内。我该不会如此幸运到问的全会吧。

是的,答案就是不会,我就是没有幸运到全会。

话不多说,接下来就回顾下面试题。

如何实现新手指引

关于这个问题我写过使用driver.js库和Vue Tour实现的新手指引。

使用js实现如下:

<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>新手指引功能</title><style>* {margin: 0;padding: 0;}body {box-sizing: border-box;}.stepBlock {background-color: burlywood;margin-right: 20px;}.positionStyle{position: absolute;z-index: 200;}/* 蒙层样式 */.overlay {position: fixed;top: 0;left: 0;right: 0;bottom: 0;background-color: rgba(0, 0, 0, .5);z-index: 100;}</style>
</head><body><section id="mask"><section class="positionStyle" id="tip"></section><section class="positionStyle" id="curStepMask"></section></section><section style="margin:200px;"><span id="first" class="stepBlock">第一步</span><span id="second" class="stepBlock">第二步</span><span id="third" class="stepBlock">第三步</span></section><section style="margin-top:30px"><button onclick="setMask()">开始指引</button></section><script>const tipDict = [{ id: 'first', content: '这里是第1步哦' },{ id: 'second', content: '这里是第2步哦' },{ id: 'third', content: '这里是最后一步哦,点击完成按钮结束新手指引' },]let flag = 0;function setMask() {// 添加蒙层let mask = document.getElementById('mask')mask.setAttribute('class', 'overlay')setTip()}function removeMask() {// 移除蒙层let mask = document.getElementById('mask')mask.setAttribute('class', '')// 移除tip提示的子元素removeTip()removeStepMask()}function setTip() {if (flag < tipDict.length) {// 获取当前步骤的元素,以及元素的位置信息,供后续定位提示信息和覆盖信息使用const curStepEle = document.getElementById(tipDict[flag].id)const bound = curStepEle.getBoundingClientRect()// 找到id为tip的元素let ele = document.getElementById("tip")// 如果存在子元素,先移除removeTip()removeStepMask()// 创建提示信息和下一步的统一父元素,方便后续移除元素let node = document.createElement('div')// 创建提示信息let tipText = document.createTextNode(tipDict[flag].content)// 将提示信息插入到父元素node.appendChild(tipText)// 创建“下一步”按钮let nextBtn = document.createElement('button')nextBtn.innerHTML = flag === tipDict.length - 1 ? '完成' : '下一步';nextBtn.onclick = setTip;// 将按钮插入到父元素node.appendChild(nextBtn)// 设置统一父元素的位置ele.style.left = bound.x + 'px'ele.style.top = bound.y + 20 + 'px'// 将统一的父元素插入到id为tip的元素ele.appendChild(node)// 将当前步骤高亮显示let tag = flag - 1if (tag >= 0) {document.getElementById(tipDict[tag].id).style = ''}// const curStepEle = document.getElementById(tipDict[flag].id)// const bound = curStepEle.getBoundingClientRect()const curStepMask = document.getElementById('curStepMask')curStepMask.style.left = bound.x + 'px'curStepMask.style.top = bound.y + 'px'const curStepEleClone = curStepEle.cloneNode(true)curStepMask.appendChild(curStepEleClone)flag++} else {flag = 0;removeMask()}}function removeStepMask() {let ele = document.getElementById('curStepMask')let child = ele.lastElementChildif (child) {ele.removeChild(child)}}function removeTip() {let ele = document.getElementById("tip")let child = ele.lastElementChildif (child) {ele.removeChild(child)}}</script>
</body></html>// 注意元素中包含如下结构:<section id="mask"> <section class="positionStyle" id="tip"></section> <section class="positionStyle" id="curStepMask"></section>
</section>

实现思路是:

  • 点击“开始指引”:找到id为mask的元素,为该元素添加蒙层样式(setMask)
  • 添加提示信息:找到id为tip的元素,将提示信息添加为该元素的子元素(setTip)
  • 高亮当前步骤元素:找到当前目标元素,克隆目标元素,然后将克隆后的目标元素添加为curStepMask的子元素(setTip)
  • 定位tip和curStepMask的元素:curStepMask元素在当前目标元素的正上方,tip元素根据情况而定
  • 每次添加当前提示信息时要移除上一次添加的提示信息和覆盖元素(removeTip,removeStepMask)
    getBoundingClientRect

返回值是一个 DOMRect[3] 对象,是包含整个元素的最小矩形(包括 padding 和 border-width)。该对象使用 left、top、right、bottom、x、y、width 和 height 这几个以像素为单位的只读属性描述整个矩形的位置和大小。除了 width 和 height 以外的属性是相对于视图窗口的左上角来计算的。–MDN

在这里插入图片描述

图片上有一个人脸,除了脸部以外加上蒙层

方案一:

添加遮罩层,在图片上方添加一张只有人脸的图片:

<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>图片添加蒙层</title><style type="text/css">img {position: absolute;top: 50%;left: 50%;width: 300px;}.overlay {position: fixed;top: 0;right: 0;bottom: 0;left: 0;background-color: rgba(0, 0, 0, .5);z-index: 100;}</style>
</head><body><div class="overlay"><img src="../images/mask.png" style="width:200px" /></div><img src="../images/cat.png" />
</body></html>

最终实现效果:(没有用一模一样的图片,只是模拟了类似的效果)

图片
image.png

上述是在整个页面添加蒙层,若想只在图片部分添加蒙层:

<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>图片添加蒙层</title><style type="text/css">img {width: 300px;}.overlay {position: absolute;top: 0;right: 0;bottom: 0;left: 0;background-color: rgba(0, 0, 0, .5);z-index: 100;}</style>
</head><body><div style="position: relative;width: 300px;"><div class="overlay"><img src="../images/kid.png" style="width:200px" /></div><img src="../images/cat.png" /></div>
</body></html>

效果:

图片
image.png

echarts实现原理

整个ECharts库都是以canvas为基础的!canvas是一个可以在页面上固定的画图区域建立坐标系,然后通过JavaScript脚本在坐标系中绘制圆、盒、文字等
Echarts拿到数据后,通过一系列的计算,算出canvas绘制图案时所需要的数据(坐标、高度、宽度等);最终通过canvas,绘制出各色图表。
在这里插入图片描述

了解canvas吗

HTML5 元素用于图形的绘制,通过脚本 (通常是JavaScript)来完成。

标签只是图形容器,必须使用脚本来绘制图形。

可以通过多种方法使用 canvas 绘制路径,盒、圆、字符以及添加图像。

如何实现组件滑动切换效果

不使用react-transition-group

对语义化的理解
语义化就是正确的标签做正确的事。语义化的好处在于:

  • 对于开发团队而言,代码更加容易维护
  • 在css没有加载出来的情况下也能很好的展示结构
  • 有利于SEO优化
  • 更好地支持各种终端,例如无障碍阅读和有声小说等

HTML5有哪些语义化标签

常用的语义化标签有:

  • header:定义页眉信息
  • nav:导航栏
  • section:页面的组成部分
  • footer:脚注信息
  • aside:侧边栏信息,比如菜单或者广告等

less 多处用到px转换为vw 如何实现

sass中可以定义函数,接收参数并且返回计算值:

/*比如:在父元素字体大小为 12px 的容器内绘制图形交互*/
@function pxToEm ($px) {@return ($px/12) + em;
}# Sass
.box {width: pxToEm(36);
}# CSS
.box {width: 3em;
}

less中函数是内置的不能够自定义,所以可以使用混入:


/*
将宽度为 375px 的 UI 设计稿转换成使用单位 vw 来适配移动端的网页。
避免编译:~' 值 '
*/.pxToVW (@px, @attr: width) {@vw: (@px / 375) * 100;@{attr}: ~"@{vw}vw"; 
}# Less
.box {.pxToVW(75);.pxToVW(150, height);
}# CSS
.box {width: 20vw;height: 40vw;
}

vue-router中router和route的区别

  • router是路由实例对象,包含一些路由跳转方法,比如push。

  • route是路由信息对象,包含和路由相关的一些信息,比如params,location等。

vue单页面应用无刷新更新组件怎么实现的

一般被询问的点在于vue-router两种模式下如何实现的url到组件的映射。

hash模式

hash模式是vue-router的默认模式。hash指的是url描点,当描点发生变化的时候,浏览器只会修改访问历史记录,不会访问服务器重新获取页面。因此可以监听描点值的变化,根据描点值渲染指定dom。

  • 改变描点
    可以通过location.hash = "/hashpath"的方式修改浏览器的hash值。

  • 监听描点变化
    可以通过监听hashchange事件监听hash值的变化。

window.addEventListener('hashchange', () => {const hash = window.location.hash.substr(1)// 根据hash值渲染不同的dom
})

history模式

通过mode选项开启history模式,history 模式和 hash 模式的区别在于:

  1. history模式中不带有“#”,更加美观
  2. history模式当用户刷新或直接输入地址时会向服务器发送一个请求,所以history模式需要服务端同学进行支持,将路由都重定向到根路由
  • 改变url
    H5的history对象提供了pushState和replaceState两个方法,当调用这两个方法的时候,url会发生变化,浏览器访问历史也会发生变化,但是浏览器不会向后台发送请求。
// 第一个参数:data对象,在监听变化的事件中能够获取到
// 第二个参数:title标题
// 第三个参数:跳转地址
history.pushState({}, "", '/a')
  • 监听url变化
    可以通过监听popstate事件监听history变化,也就是点击浏览器的前进或者后退功能时触发。
window.addEventListener("popstate", () => {const path = window.location.pathname// 根据path不同可渲染不同的dom
})

从某种程度来说,调用 pushState() 和 window.location = "#foo"基本上一样,他们都会在当前的 document 中创建和激活一个新的历史记录。但是 pushState() 有以下优势:

  • 新的 URL 可以是任何和当前 URL 同源的 URL。但是设置 window.location[6] 只会在你只设置锚的时候才会使当前的 URL。

  • 非强制修改 URL。相反,设置 window.location = “#foo”; 仅仅会在锚的值不是 #foo 情况下创建一条新的历史记录。

  • 可以在新的历史记录中关联任何数据。window.location = "#foo"形式的操作,你只可以将所需数据写入锚的字符串中。

注意: pushState() 不会造成 hashchange[7] 事件调用,即使新的 URL 和之前的 URL 只是锚的数据不同。----MDN

vue在页面中如何监听回到上一步的操作

挂载完成后,判断浏览器是否支持popstate

mounted(){if (window.history && window.history.pushState) {history.pushState(null, null, document.URL);window.addEventListener('popstate', this.goBack, false);}
},

页面销毁时,取消监听。否则其他vue路由页面也会被监听

destroyed(){window.removeEventListener('popstate', this.goBack, false);
},

页面跳转函数

methods:{goBack(){this.$router.replace({path: '/'});//replace替换原路由,作用是避免回退死循环}
}

代码题:回文字符串

function checkStr(str) {return str === str.split('').reverse().join('')
}

场景提:一个公告栏,每一天都可以展示,当用户点击关闭后今天不再显示,明天(过了今天零点)还会显示

我想到的方案就是在localStorage中存储用户关闭公告栏的时间戳,等再次进入页面的时候判断是不是存在localStorage:

  • 若不存在则证明从来没有关闭过公告栏,那就显示;
  • 若存在,就判断时间戳和当前时间是否是同一天,不是同一天就显示

代码题:命名方式中划线改小驼峰

方案一:

function transName(arr) {let res = arr.map(e => {let items = e.split('-').map((item, index) => {if (index) {let first = item.substring(0,1)let rest = item.substring(1)return first.toUpperCase()+rest}else{return item.toLowerCase()}})return items.join('')})return res
}
console.log(transName(['A-b-cee', 'ca-de-ea', 'e-fe-eaa','f-g','mn']))

方案二:

function turnName(str){return str.replace(/-[a-zA-Z]/g,match=>match.replace('-','').toUpperCase())
}

代码题:命名方式小驼峰改中划线

let s1 = 'aBBcdE';let t = s1.replace( /[A-Z]/g, match=>'-'+match.toLowerCase());
console.log(t);

git commit之后修改上一次commit的信息

刚commit还没有push

git commit --amend

会进入vim编辑器,点击i,修改commit信息后,点击esc,输入ZZ退出。

git log 可以看见最近commit信息

刚push,修改最近一次commit

git commit --amend

会进入vim编辑器,点击i,修改commit信息后,点击esc,输入ZZ退出。

git log 可以看见最近commit信息,pull后再push到远程(但是每次pull后再push会导致覆盖原来的更改,后来直接强制推送成功了:git push origin HEAD:master --force)

修改历史push的commit信息

git rebase -i HEAD~3

表示要修改当前版本的倒数第三次状态.

这个命令出来之后,会出来三行东东:

pick:*******pick:*******pick:*******

如果你要修改哪个,就把那行的pick改成edit,然后保存退出(点击esc,输入ZZ退出)

这时通过git log你可以发现,git的最后一次提交已经变成你选的那个了,这时再使用:

git commit --amend 来对commit进行修改。

修改完成后使用git rebase --continue

然后将变化push到远程:git push origin HEAD:master --force

前端性能优化

页面渲染优化

Webkit 渲染引擎流程:

  • 处理 HTML 并构建 DOM 树
  • 处理 CSS 构建 CSS 规则树(CSSOM)
  • DOM Tree 和 CSSOM Tree 合成一棵渲染树 Render Tree。
  • 根据渲染树来布局,计算每个节点的位置
  • 调用 GPU 绘制,合成图层,显示在屏幕上
  1. 避免css阻塞:css影响renderTree的构建,会阻塞页面的渲染,因此应该尽早(将 CSS 放在 head 标签里)和尽快(启用 CDN 实现静态资源加载速度的优化)的将css资源加载

  2. 避免js阻塞:js可以修改CSSOM和DOM,因此js会阻塞页面的解析和渲染,并且会等待css资源的加载。也就是说js会抢走渲染引擎的控制权。所以我们需要给js资源添加defer或者async,延迟js脚本的执行。

  3. 使用字体图标 iconfont 代替图片图标:

  • 图片会增加网络请求次数,从而拖慢页面加载时间
  • iconfont可以很好的缩放并且不会添加额外的请求
  1. 降低css选择器的复杂度:浏览器读取选择器,遵循的原则是从选择器的右边到左边读取。
  • 减少嵌套:最多不要超过三层,并且后代选择器的开销较高,慎重使用
  • 避免使用通配符,对用到的元素进行匹配即可
  • 利用继承,避免重复匹配和定义
  • 正确使用类选择器和id选择器
  1. 减少重绘和回流:

CSS

JavaScript

  • 避免频繁操作样式,最好一次性重写style属性,或者将样式列表定义为class并一次性更改class属性。
  • 避免频繁操作DOM,创建一个documentFragment,在它上面应用所有DOM操作,最后再把它添加到文档中。
  • 为元素设置display: none,操作结束后再把它显示出来。因为在display属性为none的元素上进行的DOM操作不会引发- - 回流和重绘。用一次回流替代多次回流
  • 避免频繁读取会引发回流/重绘的属性,如果确实需要多次使用,就用一个变量缓存起来。
  • 对具有复杂动画的元素生成一个新图层
  • 避免使用table布局。
  • 尽可能在DOM树的最末端改变class。
  • 避免设置多层内联样式。
  • 将动画效果应用到position属性为absolute或fixed的元素上。
  • 避免使用CSS表达式(例如:calc())。

JS中的性能优化

  • 使用事件委托
  • 防抖和节流
  • 尽量不要使用JS动画[9],css3动画[10]和canvas动画[11]都比JS动画性能好

图片的优化

  • 雪碧图:借助减少http请求次数来进行优化
  • 图片懒加载:在图片即将进入可视区域的时候进行加载(后边有判断即将进入可视区域的方法)
  • 使用CSS3代替图片:有很多图片使用 CSS 效果(渐变、阴影等)就能画出来,这种情况选择 CSS3 效果更好

webpack优化

  • 代码压缩:html,css,js文件压缩
  • Tree shaking 去除死代码
  • babel-plugin-transform-runtime减少ES6转化ES5的冗余
  • 提升打包速度

vue

  • 路由懒加载
  • 合理使用computed和watch
  • v-for添加key
  • v-for的同时避免使用v-if
  • destory时销毁事件:比如addEventListener添加的事件、setTimeout、setInterval、bus.$on绑定的监听事件等
    第三方插件按需引入

react

  • map循环展示添加key
  • 路由懒加载
  • 使用scu,memo或者pureComponent避免不必要的渲染

前端的缓存机制

分为强缓存和协商缓存。

强缓存不需要客户端向服务端发送请求,有两种响应头实现方案:

  • Expires:值是一个绝时间,在这个时间前缓存有效,但是如果本地时间被修改,会导致缓存失效

  • Cache-control:值是一个相对时间,单位为秒,资源在这个时间内有效
    强缓存过期之后会使用协商缓存,协商缓存需要客户端向服务端发送请求,资源未过期则服务端返回304否则返回新的资源。协商缓存也有两种实现方案:

  • Last-Modified 和 If-Modified-Since:Last-Modified 表示本地文件最后修改日期,If-Modified-Since 会将 Last-Modified 的值发送给服务器,询问服务器在该日期后资源是否有更新,有更新的话就会将新的资源发送回来。但是如果本地文件被打开,会导致Last-Modified 被修改。

  • ETag 和 If-None-Match:ETag 类似于文件指纹,If-None-Match 会将当前 ETag 发送给服务器,询问该资源 ETag 是否变动,有变动的话就将新的资源发送回来。并且 ETag 优先级比 Last-Modified 高。

如何判断图片即将进入可视区域

方案1:clientHeight+scroolTop>offsetTop

<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>图片加载优化</title>
</head><body><div style="background-color: green;width:100vw;height:8000px"></div><div id="yellow" style="background-color: yellow;width:100vw;height:800px"></div><script>document.addEventListener('scroll', () => {const clientH = document.documentElement.clientHeight//获取屏幕可视区域的高度const scrollT = document.documentElement.scrollTop//获取浏览器窗口顶部与文档顶部之间的距离,也就是滚动条滚动的距离const offsetTop = document.getElementById('yellow').offsetTop//获取元素相对于文档顶部的高度if (clientH + scrollT > offsetTop) {console.log('进入可视区域啦!!')}})</script>
</body></html>

方案2:下滑过程中bound.top会越来越小

<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>图片加载优化</title>
</head><body><div style="background-color: green;width:100vw;height:8000px"></div><div id="yellow" style="background-color: yellow;width:100vw;height:800px"></div><script>document.addEventListener('scroll', () => {var bound = document.getElementById('yellow').getBoundingClientRect(); 获取元素的大小及位置var clientHeight = window.innerHeight;if (bound.top <= clientHeight) {console.log('进入可视区域啦')}})</script>
</body></html>

先整理这么多,可以关注我看更多经典面试题


http://www.ppmy.cn/news/21115.html

相关文章

Leetcode刷题Day38-------------------动态规划

Leetcode刷题Day38-------------------动态规划 1. 理论基础 文章链接&#xff1a;https://programmercarl.com/%E5%8A%A8%E6%80%81%E8%A7%84%E5%88%92%E7%90%86%E8%AE%BA%E5%9F%BA%E7%A1%80.html视频链接&#xff1a;https://www.bilibili.com/video/BV13Q4y197Wg题目链接&a…

【Spring】高并发下如何提高“锁”性能?

高并发下如何提高“锁”性能&#xff1f;前言减小锁持有时间减小锁粒度读写分离锁来替换独占锁锁分离锁粗化总结前言 在项目中&#xff0c;尤其是电商或者做游戏开发的&#xff0c;高并发是必然的&#xff0c;但在高并发的环境下&#xff0c;大家会经常使用到 锁 。 “锁” 是…

数据库管理-第五十五期 DBA(20230131)

数据库管理 2023-01-32第五十五期 DBA1 数据库管理员2 数据库3 云数据库4 “列强是我自己”&#xff1f;总结第五十五期 DBA 这两天在DBA圈子里有几篇文章比较火&#xff0c;《你怎么还在招聘DBA?》&#xff0c;《云数据库是不是智商税&#xff1f;》&#xff0c;《你怎么不招…

PyQt5编程基础 2.1 GUI程序的基本框架

文章目录 创建纯代码GUI程序 创建目录 新建程序 创建GUI程序的基本过程(代码分析) 导入模块 创建应用程序 创建窗体 使用窗体类的GUI程序框架 创建项目目录 窗体设计 修改窗体的windowTitle 放一个label 放一个Push Button 保存窗体 代码设计 将QtApp中的ui文…

图例legend语法及设置

(1)设置图例位置 使用loc参数 plt.legend(loc‘lower left’) 0‘best’1‘upper right’2‘upper left’3‘lower left’4‘lower right’5‘right’6‘center left’7‘center right’8‘lower center’9‘upper center’10‘center’ (2)设置图例字体 #设置字体大小 fontsi…

如果把小程序业务和研发管理都放到一个平台

伴随着互联网在中国进程的发展&#xff0c;线上研发效能及业务应用软件也不落后于时代进步的脚步&#xff0c;中国软件行业从未停止过持续的创新。 2022年&#xff0c;业务应用开发正在简化&#xff0c;研发效能也在提升&#xff0c;其中不得不提软件在协同促进、研发一体化管…

网络攻击(Cyber Attacks,也称赛博攻击)

网络攻击&#xff08;Cyber Attacks&#xff0c;也称赛博攻击&#xff09;是指针对计算机信息系统、基础设施、计算机网络或个人计算机设备的&#xff0c;任何类型的进攻动作。对于计算机和计算机网络来说&#xff0c;破坏、揭露、修改、使软件或服务失去功能、在没有得到授权的…

【数据结构】动图详解单向链表

目录 1.什么是链表 1.问题引入 2. 链表的概念及结构 3. 问题解决 2.单向链表接口的实现 1.接口1&#xff0c;2---头插&#xff0c;尾插 2. 接口3&#xff0c;4---头删&#xff0c;尾删 3. 接口5---查找 4. 接口6&#xff0c;7---插入&#xff0c;删除 5. 接口8---打印 6. 注意…