啰嗦的话
本人现在大三,就读于北京师范大学珠海分校的前端小菜鸡。受人蛊惑,1月份开始寻找暑期实习,经历十分坎坷。因为也拿到自己心爱的offer啦,有的公司也已经稳了,等HR面或者等offer啦,所以特来分享一下俺的经历哈哈哈,希望对大家有所帮助!!
心里准备
没有名校光环,没有大厂实习经历,没有ACM金牌,一无所有,唯有坚持、努力、思考可以帮助我们
常见QA
这些俺就没有研究太多了哈哈哈,就简单扯一点点噗噗
前端技术学习路径
我个人的话,是这样子学的噗噗
graph LR
css-->js
js-->dom
React-->Webpack
Webpack-->Taro
其实说实话,对于技术栈这些东东我倒也没有太仔细的去研究过噗噗,大概就是以下这些吧:
- React/Vue
- Webpack
- Babel
- Html5
- Css3
- Typescript
- Sass/Less
- Git
基本都是平时可能做项目会碰到,比较常见的东东
前端框架学习
因为我是大一时候接触React
的,所以也是情有独钟,Vue也只是了解一些基本的原理还有使用方法,没有深入研究。俺觉得如果要研究研究框架的话。就这样子吧!
- 了解框架出现的原因
- 了解框架解决了那些问题/难点
- 了解框架基本语法、使用方式
- 了解框架的编码规范
- 了解框架的坑、以及出现的原因
- 了解框架实现的原理
- 了解框架的源码
- 自己写一个框架(划掉
大厂算法/笔试
这个东东其实我倒也没有感受的太深,就是我的感受就是,字节跳动的算法要求会比别的大厂会高(来自一面挂的小菜鸡)
笔试题
因为今年阿里内推没有笔试,TX也还没到常规批的笔试,就只经历过美团、快手的笔试。大家可以去看一下他们的笔试题,反正俺自闭了~
基本就几个方向吧,大家可以去leetcode
疯狂刷题打卡!
- 动态规划
- 图论
- DFS/BFS
- 贪心算法
- 排序
- 堆
- 数组/字符串
代码评测题/面试中的笔试
大家可以看看阿里跟TX的代码评测题,其实他们出题的感觉挺像的。基本流程都差不多
一般分为3 - 4题吧
- 第一题一般是一道leetcode难度easy/medium难度的算法题,都是比较常见的吧,一般是链表/数组/字符串
- 第二、三题一般是结合实际情况的算法题,今年常见的是DFS的题型,例如模拟
css选择器
来找节点,或者求加载依赖
的顺序。 - 最后一题一般是一个代码综合题,一般做不出来的,时间太短了,像什么模拟贪吃蛇啊,或者写一个React组件啊之类的
或者说可能是纯实践的操作题,这些基本都是我面试中遇到过的东东,例如:
- 实现深拷贝
- 实现观察者模式/订阅发布
- 实现下划线形式转换大驼峰(a_bb_ccc -> ABbCcc)
- 实现排序
- 实现函数柯里化
- 实现函数扁平化
大厂前端的要求
这个的话,其实我感受不是很明显,就我而言吧,我觉得他们想要的是,对原理的东西一定要了解/熟悉,有做一定的实践。例如`:
面试官:
webpack
,babel
有使用过吗?
面试官:那你自己写过吗?
类似这种,不仅要我们了解,会使用,还需要知道一些原理,并且自己会加以改进。
无论什么都是这样的,再比如像是React
。他们或许不会问你怎么使用,他们喜欢问:
面试官:
keys
的作用,如果列表元素重新排序,是否会重新渲染
面试官:setState
异步or同步,平时有遇到过吗
面试官:React的阻止冒泡怎么样的,跟原生有什么区别
等等之类的东东,就是一些我们平时可能不会在意的小坑,或者需要注意的东西。需要我们不仅会用也要知道为什么这样用。
前端复习重点
当然还是基础优先啦~
- 网络
- 浏览器
- css
- js
- 性能
- 框架
等等这些,就我而言,其实我也不知道什么是重点,但是我觉得前端性能优化方面很多面试官都喜欢问
- 常见的性能优化方式
- 你如何发现性能不好
- 如何发现内存泄漏
- 怎么提高首屏渲染速度
- 如何优化接口访问
- 如何实现高帧率动画
- 性能优化的指标
等等这些,关于性能方面的东西,感觉会比较常问
个人建议
前期准备
- 面试最重要还是得基础扎实hhhh,例如前端相关的知识点,我们可以面经或者书籍来恶补!,基础一定要扎实,做不到脱口而出也要思考一下吧大致的东东讲出来。
- 最重要还是得有自己项目,因为大厂更看重你的实践能力,以及在实践中的思考,难点的解决,所以我觉得有一个自己的项目,无论是在简历筛选或者是面试之中都很有用
- 做好平时的积累、沉淀。例如可以自己总结一些难点,或者易错的东东,发表一些博客文章,在社区中与大家分享一下,这都是不错的!
- 一定要坚持,万事开头难,可能觉得知识点基础都那么多了,面试怎么过嘛?但是付出的努力与回报是成正比的,你现在多努力,以后就会有多感谢自己当初的那份执着
- 梳好头发,换好衣服(一位被leader吐槽粉色睡衣的小菜鸡路过~)
不要紧张
面试大家都会紧张,这是肯定的,但是千万别过于紧张。我这人本来就是容易紧张的,所以导致面试的时候,经常紧张得说不出话哈哈哈,特别是刚刚开始,前几次的面试,哇,还是视频面试,紧张的说不出话hhh直抖腿
所以俺建议吼~可以起来走一走,喝口水,面试前10分钟可以看看B站,冷静冷静,就当做聊天一样就可以啦!
体现思考
我们很多人面试的时候,我们或许都会选择去看一些面经,很多基础的知识点,的确看面经会更加方便、快捷。但是这也有一个弊端...
那就是不能体现我们的 ”思考过程与能力“
举个例子
TCP三次握手
面试官:你知道TCP三次握手吗,你讲一下吧~
小菜鸡:客户端发送syn,服务端接收然后发送syn + ack包给客户端,客户端接收后发一个ack,连接成功
emmm,很好,但是这个简单的答案,但是会不会有所死板,更像是照着书本,标准答案念出来的
面试官:你知道TCP三次握手吗,你讲一下吧~
小菜鸡:客户端发送syn,跟服务器说“我要连接啦”,进入syn_send状态。
服务端接收然后发送syn + ack包给客户端,跟客户端说“我知道了,我这边ok了”,进入syn_recv状态。
客户端接收后发一个ack,跟服务端说”我要连接咯!“,进入establish状态,连接成功。
emmm,⑧错⑧错,带有了一点点自己的理解在里面,但是其实还可以加一点东东,可以再详细解释一下为什么是三次握手,而不是两次。
面试官:(给你个眼神)
小菜鸡:因为三次是为了确定双方的收发能力:第一次,确定了客户端的发送能力。第二次,服务端确定了自己的接受能力。第三次,确定了客户端的接受能力与服务端的发送能力。
再比如说,如果我们第一次握手,因为卡住了或者别的原因,导致连接请求没有发送出去,那么客户端会发起第二次连接请求,然后连接成功,之后断开。这时候!!这时候!!如果第一次握手的请求不卡了,现在发起了连接,而如果只需要两次握手,那么现在客户端与服务端就连接起来了,但是这时候客户端并没有东西要发送,所以就导致服务端资源被占用啦。
俺就是举个例子,hhhh说的对不对俺也不知道噗噗。就大概是这种思路嘛,面试官往往只是为了推敲出候选人是否有足够的思考能力,与技术潜力来承担起工作的重任。这样子可以很好的体现出我们的思考能力哈啊哈。
XSS和CSRF攻防
俺们再举个例子哈哈哈,比如说现在问xss跟csrf,大噶会怎么回答呢?
面试官:(开始你的表演)
小菜鸡:csrf就是跨站页面请求来进行攻击,一般我们添加token来防御,xss就是跨站脚本攻击,一般我们过滤一下script标签啊这些就ok
我们不妨说多一点,发挥口才!!!
面试官:(开始你的表演)
小菜鸡:csrf就是跨站页面请求来进行攻击,就比如我们现在登录了一个银行的网页,然后我们打开新的标签页,点击了一些攻击的网页,这时候因为我们刚刚登录,cookie还没有过期,我们刚刚点击的网页就会进行csrf攻击,利用cookie进行csrf攻击,钱就没了啦......
css就是跨站脚本攻击,分为XXX类,常见的比如现在有一个评论的组件,用户输入评论存储进数据库,然后别的用户访问的时候可以看到。如果这时候用户植入恶意的js代码评论,我们存储到数据库中,那样别的用户访问就会被攻击啦!我们可以通过过滤尖角号,或者把他转换成html实体来防御......
举举例子~更加生动!面试官更能理解你的意思!
所以俺建议吼~我们看面经之后,或许可以总结一些例子,或者一些深入的东东,例如“为什么”,“怎么来的”这些东东,面试的时候可以发挥口才疯狂吹!
适当引导
面试过几轮之后,有了一定的经验,你就会发现,面试官一般会跟着你说的东西,或者根据你的简历来进行提问。所以,其实我们可以适当的引导一下面试官问你熟悉的东东。比如......
面试官:优化性能?
小菜鸡:balabala ... 重绘、回流 ... balbala
面试官:那你说一下重回回流吧~
小菜鸡:(舒服了)
嘿嘿,可以通过一些关键词来引导hhhh
面试官:内存泄漏?
小菜鸡:内存泄漏有xxxx情况,我之前用React做一个项目,里面有一个监听滚动条,结果发现切换了页面还在监听,结果发现是没有取消时间监听,发生了内存泄漏,之后我通过xxx方法解决了
其实我们这里可以引导面试官往几个方面问
- 你的项目,难点等
- 使用hook的useEffect的return方法来取消事件监听
- 还有哪些内存泄漏的情况,如何解决
- 如何发现内存泄漏
所以俺的建议吼,这里只是举一个简单的例子,我们其实可以通过很多种方法,来引导面试官来问我们熟悉的东西,而不是被面试官带进他自己的节奏,把你问倒hhhh
项目难点
如果有自己的项目,那么有一个特殊的难点会显得尤为重要(俺因为没有,被怼的好惨hhhh)最好呢,是一个网上不能轻易找到的功能或者设计。这样会凸显自己~嗯!很强!就决定是你了。
或者是一个系统整体的架构之类的,体现出自己对于产品的理解很深哈哈哈。
再或者,可以针对自己现在的项目,总结出一个功能点计划,现在没有不代表未来没有,也可以表现的出自己也了解过相关的知识,知道大体的方向,只不过现在还没有实施,还在计划之中,体现自己很有热情!!
热情热情
热情很重要嗷,这个部分科班非科班,本科还是研究生。无论是谁,热情总能让面试官对你有好的印象。无关时间长短,只是自己的心态热情。对一个功能难点深入探究,对技术原理反复推敲,为自己的项目作出多大多大的努力。俺觉得都是十分好的东东!
稍加思索
面试的时候,问到不会的东东很正常,但是我个人觉得不要立刻说不会,其实可以稍加思索,然后想一想问题前后的联系,然后说一下自己的理解。向面试官请求引导,看看能不能答出来。如果实在不行,也可以跟面试官说,这方面还需要加强,面试结束之后自己再查查资料补一补。学习的精神很重要。
虚心请教
很多人觉得面试官很凶,很有压力,但其实我们应该是抱着学习的心态去面试的。面试只是查漏补缺的过程。我们面试结束之后,其实可以询问面试官可否加一下好友之类的。然后可以询问他一些人生的建议、技术的指导等等。厚着脸皮问,不要担心被嫌弃就好啦哈哈哈。我就是这样问一个面试官,才学到了很多东西,项目的难点,或者技术的思考之类的东东。
部分面经
阿里の盒马X数字农业事业部
初面
初面是聊得最久的一次了,一个多小时了吧,不过初面的面试官真的很让人感动一直在鼓励我,“好啊好啊”,“没关系没关系”,啊太棒了,给俺这个小菜鸡很多信心hhhh
- 输入url到页面展示
- 浏览器存储
- 如何实现继承
- 跨域,常用哪个,解释一下
- 缓存
- 重绘回流
- 性能优化
- React优势
- React生命周期
- React最佳实践
- React新特性
- 如果列表组件要新增一些内容,例如标题,简介等,你会怎么对代码进行修改(容器组件 -> 展示组件)
- csrf 和 xss
- flex
- 判断是否为数组
- typeof arr === 'object'
- 浏览器事件循环,node事件循环
- 事件委托
- webpack流程,插件
- koa源码
- koa洋葱模型
- mobx原理
- 首屏优化
- async/await Promise
- 盒模型
- babel原理
- Taro原理
一面
一面俺就放放笔试题还有俺自己做的情况吧哈哈哈哈,一面的面试官跟俺说拓扑排序,俺才知道原来还有这种东西(流泪...
笔试题目
- 给定一个链表,判断链表中是否有环,比如下图这种即为有环链表。 加分项:使用空间复杂度 O(1) 实现
- 分析一个项目的依赖结构,并按依赖优先级排序。 已知一个项目的依赖结构,期望在前端通过 loader 的方式异步加载相关的组件,而我们期望依赖在加载的过程中:
- 每一个依赖被加载后都会被立刻执行,那么如果要争取加载一个依赖,则其子依赖都应该优先被加载
- 每一个依赖不希望在钱多出现冗余的情况,若依赖出现多版本的情况,则默认使用更新的版本,比如已知项目依赖结构为(其中 @ 后面的为依赖版本号):
ProjectA
- a@0.1.0
- d@0.2.0
- c@0.1.0
- b@0.1.1
- e@0.1.2
- c@0.1.2
- c@0.2.0
则其中一种输出的依赖优先级排序为:
['d@0.2.0', 'c@0.2.0', 'a@0.1.0', 'e@0.1.2', 'b@0.1.1']
输出分析: 为了让 a 加载后可以争取执行,则必须先加载 d 和 c,b 的加载同理,又因为在整个依赖关系下,c 的最新版本为 0.2.0 于是有了如上的输出结果。
- 请用 React 实现一个搜索框组件,功能包括:
- 输入文本字数限制
- 可配置输入文本约束,比如仅限输入数字
- 用户输入时可支持关键字搜索,并出现下拉框展示相关项
俺的答案
- 第一题leetcode原题来的,环形链表好像是,可以用快慢指针或者简单的集合
const cycle1 = function (node) {
let set = new Set()
while (node) {
if (set.has(node))
return true
else
set.add(node)
node = node.next
}
return false
};
const cycle2 = function (node) {
let start = node
let end = node.next
while (start !== end) {
// 没有环就null
if (end === null || end.next === null) return false
start = start.next
end = end.next.next
}
return true
}
- 第二题的话我拿到题目第一个想到的就是DFS来寻找那些依赖,然后最后再对依赖这些进行版本比较(其实应该用集合、还有拓扑排序来优化)
这题有大佬在评论区指出错误啦!之前那个版本是比较字符串,但是忽略了多位数字版本的情况,例如
b@0.2.22
与b@0.2.3
,结果应该是前者,但之前版本是输出后者,现在修改了一下!好嘞!
function update(npmList) {
let versions = {}
let res = []
// 比较版本号
function cmp(a, b) {
const versionListA = getVersion(a).split('.')
const versionListB = getVersion(b).split('.')
for (let index = 0; index < 3; index++) {
const versionA = parseInt(versionListA[index])
const versionB = parseInt(versionListB[index])
if (versionA > versionB) return a
else if (versionA === versionB) continue
else return b
}
return a
}
// 获得版本号
function getVersion(str) {
return str.substr(str.indexOf('@') + 1)
}
function dfs(npmList) {
if (npmList.length === 0) return
npmList.forEach((npm) => {
const { name, deps = [] } = npm
// 先遍历他们的依赖
dfs(deps)
let key = name.substr(0, name.indexOf('@'))
// 如果依赖不存在则添加,若已存在,则取最新版
if (!versions[key]) {
versions[key] = name
} else {
versions[key] = cmp(versions[key], name)
}
// 添加进最后的加载列表
res.push(key)
})
return
}
dfs(npmList)
// 去除重复项,然后将包名转换为依赖名,eg: a -> a@0.1.0
return [...new Set(res)].map(key => versions[key])
}
- 第三题的话,我粗略写了一下噗,写的也不是很好,用React整的
// 第三题React部分第三题React部分第三题React部分第三题React部分第三题React部分
import React, { Component } from 'react';
import './input.css'
function debounce(fn, delay = 500) {
let timeout = null
return function (e, ...args) {
e.persist && e.persist()
timeout && clearTimeout(timeout)
timeout = setTimeout(() => {
fn.call(this, e, ...args)
}, delay)
}
}
class Tips extends Component {
render() {
const { tipsList } = this.props
return tipsList && tipsList.length !== 0 ? (
<div className="tips__container">
{tipsList.map((item, index) => {
return (
<a href="#" key={index} className="link">{item}</a>
)
})}
</div>
) : <div></div>
}
}
export default class Input extends Component {
constructor(props) {
super(props);
this.state = {
keyWords: [
'前端工程师1', '前端高级开发1', '后端工程师1', '测试开发1', '项目主管1', 'dress', 'Recent', '123456', 'awdad1'
],
inputValue: '',
inputType: 'text',
inputMaxLen: 20,
wordsList: []
}
this.handleInput = debounce(this.handleInput, 200)
this.handleMaxLenChange = debounce(this.handleMaxLenChange, 400)
}
handleInput = (e) => {
const { target: { value } } = e
const { keyWords } = this.state
const tipsList = !value
? []
: keyWords.filter(item => {
const res = item.search(new RegExp(value, 'i'))
return res !== -1
})
this.setState({
inputValue: value,
tipsList
})
}
handleTypeClick = (e) => {
const { target: { name } } = e
this.setState({ inputType: name })
}
handleMaxLenChange = (e) => {
const { target: { value } } = e
const { inputValue } = this.state
const newInputValue = inputValue.substr(0, +value)
// 如果设置最大长度小于现在关键词的长度,则截取一下
this.input.value = newInputValue
this.setState({ inputMaxLen: value, inputValue: newInputValue })
}
render() {
const { tipsList, inputType, inputMaxLen } = this.state
return (
<div className="container">
<div className="control__container" onClick={this.handleTypeClick}>
<button name="text">文本</button>
<button name="number">数字</button>
<span>最大长度: </span>
<input type="number" placeholder="默认: 20" onInput={this.handleMaxLenChange} />
</div>
<div className="input__container">
<div className="input__wrap">
<input
ref={input => this.input = input}
placeholder="请输入关键词"
type={inputType}
maxLength={inputMaxLen}
onInput={this.handleInput} />
<button>搜索</button>
</div>
<Tips tipsList={tipsList} />
</div>
</div>
)
}
}
// 第三题CSS部分第三题CSS部分第三题CSS部分第三题CSS部分第三题CSS部分第三题CSS部分
.container {
width: 600px;
height: 400px;
margin: 0 auto;
padding: 30px;
background: #fff;
}
.input__container {
margin-top: 30px;
}
.input__wrap {
display: flex;
align-items: center;
}
.input__wrap input {
box-sizing: border-box;
width: 85%;
height: 50px;
padding: 0 10px;
border: #666 1px solid;
border-right: 0;
outline: none;
}
.input__wrap button {
cursor: pointer;
box-sizing: border-box;
width: 15%;
height: 50px;
color: #fff;
font-size: 20px;
border: none;
border: #666 1px solid;
outline: none;
background: #1890ff;
}
.control__container {
display: flex;
align-items: center;
}
.control__container button {
cursor: pointer;
width: 50px;
height: 30px;
margin-right: 10px;
color: #fff;
outline: none;
border: #333 1px solid;
border-radius: 8px;
background: #1890ff;
}
.control__container span {
margin-left: auto;
margin-right: 10px;
color: #666;
font-size: 14px;
}
.tips__container {
overflow-y: scroll;
max-height: 200px;
border: #333 1px solid;
border-top: 0;
}
.tips__container .link {
display: block;
height: 30px;
padding: 5px 10px;
color: #666;
line-height: 30px;
text-decoration: none;
}
.tips__container .link:hover {
color: #fff;
background: #666;
}
input::-webkit-outer-spin-button,
input::-webkit-inner-spin-button {
display: none;
}
二面
二面主要是结合项目来问的,抓住一个功能发散开来,例如我项目的聊天室的功能,吓得我好慌好慌hhh,不过面试官人很好一直引导我,特别是那些场景题,引导我去思考,啊,太感动了!!!
- 项目の各种东东
- 聊天私聊怎么做
- 聊天记录未读消息怎么做
- 聊天离线信息处理
- session会话管理如何实现(用户登录后,打开新标签页输入url访问资源)
- 访问资源权限控制
- 事件队列题
- websocket如何连接
- 做题系统组件的设计与拓展(拓展更多类型的题目,如何设计组件)
- 用户鉴权系统设计
- 为什么密码表跟用户信息表分开放
- 数据库表的设计
三面
这一面也是结合项目来问的。啊,三面的面试官真的太好了,期初我的小项目没什么难点(我都以为凉透透了呜呜呜),然后面试官给了提了几个建议,让我多去深入思考思考,面试完之后去找他请教问题,也一直很有耐心给我指导指导,啊,太棒了吧🤭
- 项目の各种东东
- 飞猪为什么挂了
- 项目难点
- 小程序登录怎么做的
- 封装了什么组件
- 建议:在线阅卷、批注、修改错别字等(canvas绘制)
- 建议:实时监控每个同学的进度(选择答案后之后教师端更新/摄像头监控)
- a与b聊天,将他们的记录,多选,然后合并发给c,如何设计
- 除了编译成小程序,有试过app吗
四面
四面应该是总监面,还是得感谢三面的面试官给我提的建议,之后做出来之后,发现这个东东可以作为项目的一个难点来吹哈哈哈!四面主要还是围绕项目来问,我个人觉得关注的更是自己的思维、对技术的认识、对自己未来的发展规划等宏观的内容
- 项目难点(canvas绘制公式
- websocket实现,聊天功能的实现(心跳检测,断线重连
- 项目の细节
- 聊天信息的一致性,时序性
- 目标、具体想通过实习学到什么
- 技术规划,之后学些什么
五面
五面是交叉面,心惊胆跳呜呜呜,希望不要挂我...五面问的大多是基础方面的内容,不过也是结合项目来问的,这一面面试官主要关注的是
性能
方面的内容,例如数据埋点啊、页面加载时间、接口响应时间等一系列关于性能方面的问题,他希望的是数据量化的一个东东,具体的实现,达成了什么目标等
- 项目做了那些事情
- 小程序运行池
- 小程序和H5的区别
- 缓存存在哪(强缓存、协商缓存分别通过什么字段保存
- React与Vue的区别
- React的优势
- Taro编译的机制
- Taro支持的端有哪些
- node的机制、优势
- 项目的难点,如何解决,遇到的问题
- 如何监控性能
- 尝试做了哪些性能上的优化
- 收集用户信息?数据埋点?性能指标?量化指标?
- 资源大小,加载速度,页面渲染时间,接口访问时间
- 如何优化node后台的接口(sql优化,表结构重写
- 使用什么服务器,部署在什么操作系统上
- 多人同时访问接口测试过吗?最高承载多少
- webpack如何减小资源打包大小
- 擅长什么
- 你的优势是什么
- 目标?规划?
腾讯のWXG开放平台小程序基础部
一面
一面是笔试 + 面试,俺也放放题目跟俺的答案吧!
笔试题目
- 实现⼀个函数 reverse(a, n) ,反转⼀个含有 n 个整数的数组 a(直接在数组a上操作,元素交换次数 尽可能少,不能使⽤js Array 类内置属性和⽅法)。
- 实现⼀个函数 countLongest(tree) ,输⼊⼀棵⼆叉树,返回⼆叉树中距离最⻓的两个叶⼦节点之间 的距离。
var x = [0, 1, 2, 3]
reverse(x, 4) // x = [3, 2, 1, 0]
var y = [1, 2, 3, 4, 1]
reverse(y, 5) // y = [1, 4, 3, 2, 1]
var tree1 = {
value: 1,
left: {
value: 2
},
right: {
value: 3
}
}
countLongest(tree1) // 2
var tree2 = {
value: 1,
left: {
value: 2,
left: {
value: 3,
left: {
value: 6
}
},
right: {
value: 4
}
},
right: {
value: 5
}
}
countLongest(tree2) // 4
- 在前端开发中,通常会把多个js⽂件合并成⼀个⽂件,以减少⽹络请求次数,达到优化加载速度的⽬ 的,但是当⽂件之间存在依赖关系时,对js合并的顺序,会有⼀定的要求,⽐如 A.js 依赖了 B.js,那打 包后的⽂件,B.js 需要排在 A.js 的前⾯。 实现⼀个函数 resolve(tree) ,根据js的依赖关系树 tree,输出合理的打包顺序的数组(结果可能不 唯⼀,输出其中⼀种即可)。
样例
var tree1 = {
name: 'main.js',
require: [{
name: 'A.js'
}, {
name: 'B.js'
}]
}
resolve(tree1) // ['A.js', 'B.js', 'main.js']
var tree2 = {
name: 'page.js',
require: [{
name: 'A.js',
require: [{
name: 'B.js',
require: [{
name: 'C.js'
}]
}]
}, {
name: 'D.js',
require: [{
name: 'C.js'
}, {
name: 'E.js'
}]
}]
}
resolve(tree2) // ['C.js', 'E.js', 'D.js', 'B.js', 'A.js', 'page.js']
- 给定⼀个整数数组 a,实现⼀个函数 countMax(a) ,计算出从 a 中选择出多个不相邻元素组成最⼤的 和是多少。
样例
var x = [1, 4, 5, 3]
countMax(x) // 7
var y = [3, 12, 6, 2, 4]
countMax(y) // 16
俺的答案
- 就是简单的倒置hhh
function reverse(arr) {
let len = arr.length
for (let start = 0; start < Math.floor(len / 2); start++) {
let end = len - start - 1;
[arr[start], arr[end]] = [arr[end], arr[start]]
}
return arr
}
- 这题是leetcode原题好像,就算算深度
function countLongest(tree) {
if (!tree) return 0
let res = 0
function dfs(node) {
if (!node) return 0
const leftMax = dfs(node.left)
const rightMax = dfs(node.right)
res = Math.max(leftMax + rightMax, res)
return Math.max(leftMax, rightMax) + 1
}
dfs(tree)
return res
}
console.log(countLongest({
value: 1,
left: {
value: 2
},
right: {
value: 3
}
}))
console.log(countLongest({
value: 1,
left: {
value: 2,
left: {
value: 3,
left: {
value: 6
}
},
right: {
value: 4
}
},
right: {
value: 5
}
}))
- 第三题是不是很眼熟哈哈哈,跟盒马一面的笔试题好像(其实我发现很多面试笔试题都有这相关的影子)还是DFS来找
function resolve(npmList) {
const res = []
function dfs(npmList) {
if (npmList.length === 0) return
npmList.forEach((npm) => {
const { name, require = [] } = npm
dfs(require)
!res.includes(name) && res.push(name)
})
return
}
dfs(npmList)
return res
}
console.log(resolve([{
name: 'page.js',
require: [{
name: 'A.js',
require: [{
name: 'B.js',
require: [{
name: 'C.js'
}]
}]
}, {
name: 'D.js',
require: [{
name: 'C.js'
}, {
name: 'E.js'
}]
}]
}]))
- 用动态规划来找
function countMax(arr) {
const len = arr.length
const dp = new Array(len).fill(0);
dp[0] = arr[0]
dp[1] = arr[1]
dp[2] = arr[0] + arr[2]
for (let i = 3; i < len; i++) {
dp[i] = arr[i] + Math.max(dp[i - 2], dp[i - 3])
}
return Math.max(dp[len - 1], dp[len - 2])
}
console.log(countMax2([1, 4, 5, 3]))
console.log(countMax2([3, 12, 6, 2, 4]))
面试内容
- 项目
- 为什么用token不用cookie
- 跨域(前端跟前端的跨域,iframe之间)
- xss
- React与Vue的对比
- Taro与其他多端框架
- 主要还是项目发散
- 如何实现轮播图
二面
二面基本都是一些基础吧,但是就有些地方会深入去挖这样子
- https原理,握手过程(何时对称/非对称,谁先谁后,为什么这样)
- 常见的优化
- webp格式优化了多少
- 缓存以键值形式存在浏览器,键是什么,值是什么
- 设计一个缓存策略,(hash值)
- React的key
- React与Vue的区别
- Taro与小程序官方框架的区别
- 小程序运行池
- React列表key固定,顺序调换会渲染吗(不会)
- 如何判断性能瓶颈
- 项目の各种东东
三面
三面感觉还不够二面难,问的比较常见吧应该说,然后也是问问项目这样子
- 算法:判断数组中是否存在两个数相加等于目标值,给出多种思路与时间空间复杂度(暴力循环,排序后循环剪枝,动态规划)
- es6的class如何实现私有变量(symbol + 闭包)
- 如何进行性能监控
- 常见的性能优化方法
- 内存泄露如何发现,如何解决
- 垃圾回收机制
- 跨域(cors + jsonp + 其他不常见的跨域方法)
- 浏览器缓存
- 实现深拷贝,深拷贝的用途
- xss、csrf
- cookie与token的工作原理,区别,如何设计
- http1.1、http2.0
- http无状态
- websocket是什么协议,如何连接
- websocket有什么优势,对比轮训呢
- 事件循环
- setTimeout是否准时,如果不是则应该提前还是延迟
- webpack流程
- 常见的http状态码
- babel原理、taro原理
- map中的键值会不会被回收(weakMap,weakSet等)
- 项目....难点、设计、收获
- 平时如何学习
美团到店事业部
一面
- 项目
- 原型链
- 继承
- instanceof
- 事件循环
- 异步任务有哪些,底层如何实现(不会
- websocket
- 轮询的弊端
- websocket的弊端与优势
- TCP三次握手
- 为什么需要三次握手
- 如果两次握手会发生什么,保持不必要的链接主要是浏览器端还是服务端收到影响大
- TCP的拥塞问题(不会
- xss和crsf
- 跨域(种类,如何使用
- 同源策略
- 跨域为了解决什么问题
- cookie和token
- 如何使用token,设计
- 意向城市
- 为什么选择前端
- 前端学习的规划
- koa中间件模型,洋葱模型
- 三道算法
1. 合并两个有序链表
2. 找出数组第K大的数
3. 晨晨是个爱跑步的孩子,这一天,他准备跑正好k米。
他所在的城市的道路可以看做n个点,m条无向边组成的图,
每条边有一个固定的长度。 晨晨有强迫症,
他跑步前往一个目的地一定要走最短路(当然有多条最短路就可以随意选择了)。
晨晨希望知道,他正好跑k米能走到的目的地的个数。
注意,目的地可能在图中的点和边上,且该目的地距离晨晨的起点的最短路正好k米。
若k大于所有路径之和自然不存在这样的目的地,输出结果自然为0。
二面
- function和箭头函数
- 箭头函数有什么特殊的地方
- React的生命周期哪些是不安全的,为什么
- 为什么会出现React Hooks
- Memo跟useCallback的区别与联系
- hooks模拟生命周期
- 内存泄漏
- 如何监控内存泄漏,如何发现(全局变量,闭包,监听事件,定时器
- SPA的优缺点
- 首屏加载如何优化
- webpack的plugin跟loader的区别
- css垂直居中
- margin相对于谁
- 移动端用什么布局
- 如何还原设计稿
- em、rem
- margin-top百分比相对于什么
- 图片格式之间的区别
- 如何检测浏览器不支持webp(img onerror
- Promise的reject跟catch,场景,你如何使用
- class 与 function的区别
- class实现静态变量
- for in 和 Object.keys的区别
- 类继承的特点
- ES6的Map与对象有什么区别
- git rebase/stash/commit
- 不用div如何包裹多个元素(Fragment,<><>).
- 原型链,作用,如何实现,原理
- 盒模型
- 笔试题:数组扁平化排序去重
- 笔试题:实现柯里化函数
三面
- 项目成就,经历,心得(疯狂追问
- css移动方块(css3,setInterval,requestAnimationFrame)
- 为什么requestAnimationFrame能够做到60帧
- javascript引擎,v8引擎,垃圾回收
- v8引擎跟别的有什么区别
- 代码编译大致流程
- babel
- http跟https区别,具体
- 如果https发来证书,但是我没有CA的公钥怎么办(用久的请求CA新的
- 堆跟栈的区别
- 还有别的什么内存块
- 垃圾回收
- 如何手动垃圾回收(定时器,监听事件,对象等
- 两个this指向的问题
- 笔试部分
实现自定义数组下的排序方法(挂载到数组原型)
实现下划线字符串转换大驼峰(asf_ad_ada_adwa -> AsfAdAdaAdawa)
实现发布订阅(on,off,emit,once)