我正在参与「启航方案」
前语
间隔上篇面试题的共享现已过去半个月了,经历了面试官的灵魂拷问,笔者也在这半个月收获、成长了许多,所以笔者在本篇文章将会共享几家公司实习岗位的面试题(包含莉莉丝、哈啰、滴滴),期望对咱们有帮助~ 一起前进哦~
面经共享
莉莉丝 凉经
莉莉丝是一家游戏公司,所以调查相对来说更注重思维能力,面试官会比较积极的引导,答不出来面试官也会讲解一遍。
-
瀑布流列表关于恳求过的数据是否做优化?了解虚拟翻滚(虚拟列表)吗?
这题是依据我的项目介绍问的。虚拟列表是在处理用户翻滚时,只改动列表在可视区域的烘托部分,它能够提高页面烘托功能,削减数据过多时的卡顿。
下面是一个简略的虚拟列表demo:
function FixedSizeList(props){
const {{containerHeight,itemCount,itemHeight}} = props; // 容器高度,列表数量,列表项高度
const [scrollTop,setScrollTop] = useState(0)
const items = [];
// 烘托列表第一个index
let startIdx = Math.floor(scrollTop / itemHeight);
// 烘托列表最终一个index
let endIdx = Math.floor((scrollTop+containerHeight)/itemHeight);
// 在可视区外缓存列表项数量
const paddingCount = 2;
startIdx = Math.max(startIdx - paddingCount,0);
endIdx = Math.min(endIdx + paddingCount,itemCount-1)
for(let i = startIdx;i <= endIdx;i++) {
items.push(<Component key={i} index={i}
style={{height:itemHeight}}/>)
}
const top = startIdx * itemHeight;
const contentHeight = itemHeight * itemCount;
return (
<div style={{height:containerHeight,overflow:'auto'}}
onScroll={
(e) => {
// 处理烘托有导致的白屏问题
// 改为同步更新
flushSync(() => {
setScrollTop(e.target.scrollTop)
})
}
}
>
<div style={{height:contentHeight}}>
<div style={{height:top}}></div>
{items}
</div>
</div>
)
}
-
重排重绘
重排:当
DOM
的改动影响了元素的几许信息(DOM
目标的位置和尺度巨细),浏览器需求从头核算元素的几许特点,将其安放在界面中的正确位置,这个进程叫做重排。修正元素的尺度、增加删去可见的元素、操作Offset
相关特点等都会引起重排。
重绘:当一个元素的外观发生改动,但没有改动布局,从头把元素外观绘制出来的进程,叫做重绘。如修正元素的色彩等。
怎样削减重排、重绘:- 分离读写操作:即在运用
offset
相关特点进行读操作之前,完结一切改动DOM
的写操作。 - 会集改动样式:将样式一致写在一个类名上,再将该类名加到特点上。
- 离线修正
dom
:在要操作dom之前,经过display躲藏dom,当操作完结之后,才将元素的display特点为可见;或者经过运用DocumentFragment创立一个dom
碎片,在它上面批量操作dom,操作完结之后,再添加到文档中,这样只会触发一次重排。 - 设置
position
特点为absolute
或fixed
- 启用
gpu
加速:transform: translate3d(10px, 10px, 0);
- 分离读写操作:即在运用
-
虚拟DOM
-
类组件/函数组件开发差异
-
完结自界说hook (对能够上下/左右滑动的滑块界说hooks)
平时自己写自界说hooks比较少,所以这题面试官引导了挺久,仍是没写出来/(ㄒoㄒ)/
const onSlide = (dir) => { console.log(dir) } const { domRef:domRef1 } = useSlide(onSlide,'v'); const { domRef:domRef2 } = useSlide(onSlide,'h'); return ( <div className="App"> <input type="range" ref={domRef1}/> <input type="range" ref={domRef2} style={{transform:'rotate(-90deg)',marginTop:'55px'}}/> </div> )
// 自界说 hooks useSlide const useSlide = (cb,direction) => { const domRef = useRef(null); const handleUp = (e) => { if(direction==='v'){ // cb(e.clientX) cb(e.target.value); }else if(direction==='h'){ // cb(e.clientY) cb(e.target.value) } } useEffect(() => { domRef?.current?.addEventListener('mouseup',handleUp) return () => { domRef?.current?.removeEventListener('mouseup',handleUp) } },[]) return { domRef } }
-
js数据类型,简略数据类型和杂乱数据类型的差异
-
原型链 原型目标
-
Promise与js事情机制
-
数组扁平化(仓库写法,非递归)
const flatter = (arr) => { let stack = [...arr]; let res = []; while(stack.length){ let num = stack.pop(); if(Array.isArray(num)) { stack.push(...num); } else { res.push(num); } } return res.reverse(); }
-
玩石子游戏(算法)
一共n颗石子,两个人轮番拿,每次能够拿1或2或3颗,最终一次将石子取完的人输,判别自己最终是赢是输?我一开始想能不能用动态规划去解,面试官说我想杂乱了。当最终剩 4 颗石子的时分,不管咱们怎样取都能够取胜;当剩 8 颗石子的时分,咱们一定能够控制最终剩下 4 颗石子…所以咱们只需 判别石子的数量是否是 4 的倍数 即可判别自己最终是否能够取胜。
哈啰 已oc
面试官十分年青,好像就现已是技术专家了,好羡慕,人也很好,整面子下来的感觉仍是不错的。
-
cors跨域原理
经过设置呼应头
Access-Control-Allow-xxx
字段来设置拜访的白名单、可答应拜访的办法等module.exports = async (ctx,next) => { // 设置呼应头 // 答应拜访跨域服务的白名单 *答应一切 ctx.set('Access-Control-Allow-Origin','*'); ctx.set('Access-Control-Allow-Headers','Content-Type'); ctx.set('Access-Control-Allow-Methods','GET,POST,OPTIONS'); // OPTIONS 获取资源答应拜访的办法 // 其实在正式跨域之前浏览器会依据需求建议一次预检也便是option恳求用来让服务端回来答应的办法 await(next()) }
-
跨域阻拦 是浏览器阻拦仍是服务器阻拦
跨域是浏览器的同源策略形成的,同源是指”协议+域名+端口”三者相同,为了保证浏览器安全对呼应的数据进行阻拦,若发现对错同源的资源浏览器进程会把呼应体丢掉。所以跨域阻拦是浏览器进行阻拦。
跨域是为了阻挠用户读取到另一个域名下的内容,跨域并不是恳求发不出去,恳求能发出去,服务端能收到恳求并正常回来成果,仅仅成果被浏览器阻拦了。Ajax 能够获取呼应,浏览器以为这不安全,所以阻拦了呼应。经过表单的办法能够建议跨域恳求,由于表单并不会获取新的内容,所以能够建议跨域恳求。
-
假设我现在在淘宝,要去百度,我还会携带上淘宝的cookie吗?
不会。在
cookie
中,domain
特点指定了 cookie 的所属域名,path
特点用来指定途径;这两个特点决议了服务器发送的恳求是否带上这个cookie
。淘宝的 cookie 和百度的域名、途径不一致,所以拜访百度不会带上淘宝的cookie
。 -
淘宝跳转到天猫页面为什么不需求从头登陆( taobao.com 和 tmall.com )?
这是由于淘宝和天猫页面设置了单点登录SSO,在多个体系的集群里,用户只需一次登陆,其他体系也会感知到用户登陆,不需求用户从头输入用户名密码登陆。
在淘宝和天猫之间部署一台专门用作登录的服务器,相当于完结一个中转站,这个中转站存放着需求共享登录状态服务运用的
session
信息,它就相当于一把钥匙,当用户进行运用跳转的时分都会来中转站看一看,假如session
存在就直接运用这把钥匙把通往另一个运用的门翻开,假如不在就得先承认用户身份(登录)制造session
钥匙存在中转站再把门翻开,用户的身份存储和身份的有用时刻都是中转站说了算,一致管理的。 -
http协议的特点
- 灵敏便利:支持传输多种形式的内容
- 牢靠传输:依据tcp/ip
- 恳求-应答:具有发送方和接收方
- 无状态:每次恳求都是独立无关的,不会记住上一次的状态
-
BEM 命名规范
B:block E:element M:modefiled 语义性好,模块化,组件化,可复用
这是面试官看到我的第一篇文章来问的,有爱好的朋友能够看看哦。BEM-实战淘宝订单模块 -
flex:1的意义, flex:1和flex:2的差异
flex 是 flex-grow ,flex-shrink ,flex-basis的缩写
flex:1
即flex-grow:1
若存在剩下空间依据剩下空间进行扩大 ;flex-shrink:1
若空间不够,将内容缩小;flex-basis:0%
内容本来巨细 -
var a = [],为什么能够直接运用a.push(),a.pop()
a 经过目标字面量的办法生成一个数组目标实例,能够经过原型链查找办法,运用到
Array
原型上的push
和pop
办法。 -
var a = new A(),a 和 A 的联系,A 和 Function 的联系
a 是 A 的一个实例目标,a 的
__proto__
指向 A 的prototype
,A 的__proto__
指向 Function 的prototype
。 -
浏览器事情机制 event loop
-
Primise.then 中的微使命在下一轮仍是这一轮履行
-
commonjs之后为什么提出es molule,两个模块的特点
commonjs
导出(module.exports),导入(require)。
能够动态加载句子,发生在代码运转时,模块是同步加载的,只需加载完结才能进行后续操作;模块能够屡次加载,但只会在第一次加载时运转一次,成果会被缓存,下次 加载直接读取缓存成果,除非清除缓存。导出的值的复制的,能够修正,模块内的修正不会影响复制的值,代码犯错不好排查。esmodule
导出(export default),导入(import from)
是静态的,只能声明在文件最顶部,发生在代码编译时;导出的值存在映射联系引用,是可读的,不行修正 -
函数式组件和类组件的差异
-
usestate 重复修正屡次,会烘托屡次吗? 什么时机触发烘托?
- 假如
useState
在同步代码中重复修正屡次,只会烘托一次。由于出于功能考虑,React 会把多个setState()
调用合并成一个调用,这也是state
的批量更新机制。React 会将该 state “冲洗” 到浏览器事情结束的时分,再一致地进行更新,这时才会触发烘托。 - 而假如
setState
在异步代码(如 setTimeout、async await)中重复修正屡次,烘托会在每次修正后触发一次。
- 假如
-
redux
-
听说过依据redux的封装吗?
-
为什么本地开发更改一行代码,浏览器会部分更新那一部分?浏览器怎样知道代码变了?
这题触及到我的知识盲区了,于是面试官跟我讲解了一下,赞!
脚手架npm run dev后,会发动一个本地的服务 localhost,它依据socket
连接本地编辑器和浏览器的通讯,监听文件体系是否发生改动,当发生改动时webpack
会告诉浏览器代码发生更改,浏览器就会做相应的烘托。这块应该是热更新的知识点。 -
装修者形式
-
ts 中 record是做什么的?
Record<K,T>
构造具有给定类型T
的一组特点K
的类型。他会将一个类型的一切特点值都映射到另一个类型上并创造一个新的类型.实例:
interface EmployeeType { id: number fullname: string role: string } let employees: Record<number, EmployeeType> = { 0: { id: 1, fullname: "John Doe", role: "Designer" }, 1: { id: 2, fullname: "Ibrahima Fall", role: "Developer" }, 2: { id: 3, fullname: "Sara Duckson", role: "Developer" }, } // 0: { id: 1, fullname: "John Doe", role: "Designer" }, // 1: { id: 2, fullname: "Ibrahima Fall", role: "Developer" }, // 2: { id: 3, fullname: "Sara Duckson", role: "Developer" }
-
项目后台建立为什么选择koa?为什么不是express?
-
说说个人的亮点
滴滴 已oc
感觉面试官问的问题可答复面比较广,所以能够挑自己擅长的范畴说~ 而且面试官比较和蔼,让我不要紧张。面试官直接就跟我约了二面的时刻。
-
css布局办法
说了以下四种布局办法,然后以水平垂直居中为例,具体的说了下每种布局办法是怎样运用的。
- flex
- grid
- float
- position
-
float脱离文档流怎样做处理
我大概说了下清起浮、高度塌陷的不同处理办法,趁便说了下BFC
-
position特点,分别相对谁定位,具体运用场景
-
js 数据类型 Symbol运用场景
-
类型判别办法
我说了三种 typeOf、instanceOf、Object.prototype.toString.call() 以及他们各自的优缺点
面试官接着问了instanceOf 原理,说完持续问了下面两个问题
Array instanceOf Array == ?(false)
Object instanceOf Object == ?(true) -
数组api,以及在项目运用场景
-
forEach map差异 运用场景
-
forEach
和map
都能够对数组的进行遍历。 -
forEach
回来值为undefined
,所以不能进行链式调用,适用于不更改数组的情况; -
map
会回来一个新数组,这个新数组由原数组中的每个元素都调用一次提供的callbackFn
函数后的回来值组成。一般用于需求修正数组的情况。 - 关于数组项是根本数据类型的数组,
forEach
和map
都不修正调用它的原数组本身,可是那个数组可能会被callbackFn
函数改动; 关于数组项是引用数据类型的数组,用forEach
和map
都能够改动它的特点值。
又问:给目标数组中目标的每一项加一个特点,用 forEach 仍是 map?
这儿用forEach
会更好,直接在原数组上修正即可,假如用map,还要将回来的成果从头赋值给本来的数组变量,语义不好。 -
-
手写代码 将目标数组转为目标
const array = [ { code: 101, name: '北京', }, { code: 102, name: '石家庄', }, { code: 102, name: '江苏', children: [{ code: 102, name: '南京', },{ code: 102, name: '连云港', }] } ]
转换成:
{ '北京':{ code: 101, name: '北京' }, '石家庄':{ code: 102 name: '石家庄' }, '南京':{ code: 102 name: '南京' }, '连云港':{ code: 102 name: '连云港' } }
完结代码:
function toObj(arr) { let obj = {}; for(let item of arr) { if(item['children']!==undefined) { obj = {...toObj(item['children']),...obj}; }else { obj[item.name]=item; } } return obj; }
-
依据代码看输出 this问题
const obj1 = { hello: function () { console.log(this); // obj1 setTimeout(function () { console.log(this); // window }); } } obj1.hello(); const obj2 = { hello: function () { console.log(this); // obj2 setTimeout(() => { console.log(this); // obj2 }); } } obj2.hello() const obj3 = { hello: ()=> { console.log(this); // wondow setTimeout(() => { console.log(this); // window }); } } obj3.hello()
-
闭包 以及项目中的运用
-
防抖节省
-
vite webpack 了解多少
-
js模块化 commonjs esmodule差异
-
UMD AMD CMD
-
AMD (Asynchronous Module Definition 异步模块界说)
commonjs是同步加载的,不适用于浏览器环境,一切有了AMD CMD;
AMD是异步加载的,模块的加载不影响后边句子的运转。一切依靠这个模块的句子都界说在一个回调函数中,等 加载完之后,这个回调才会运转。AMD 的模块引进由 define 办法来界说 -
CMD (Common Module Definition)
关于依靠的模块,AMD 是提早履行,CMD 是推迟履行。CMD 推重依靠就近,AMD 推重依靠前置。 -
UMD (Universal Module Definition 通用规范模块)
一致浏览器端(AMD)和非浏览器端(commonjs)的模块化方案。- 先判别是否支持AMD(define是否存在),存在则运用AMD办法加载模块;
- 再判别是否支持commonjs(exports是否存在),存在则运用commonjs模块格式
- 前两个都不存在,则将模块公开到大局
-
AMD (Asynchronous Module Definition 异步模块界说)
-
浏览器缓存 怎样做demo的
首要针对的是前端静态资源(js css image),大大的削减了恳求的次数,提高了网站的功能(两端)
-
强缓存 设置http呼应头
- http1.0版本:
Expires
具体时刻点,客户端时刻禁绝可能会导致差错 - http1.1版本:
Cache-Control
:max-age=xxx
时刻偏移量 倒计时
- http1.0版本:
-
协商缓存
- Last-Modified
会常常更改的数据,不变则发送304。恳求数量不变,恳求体积减小- 设置呼应头:
Last-Modified
文件最近更改时刻 - 判别恳求头:
if-modified-since
==Last-Modified
发送304
- 设置呼应头:
- etag
依据文件生成哈希串- 设置呼应体:
Etag
- 判别恳求头:
if-none-match
==Etag
发送304
- 设置呼应体:
- Last-Modified
-
强缓存 设置http呼应头
-
nginx
-
跨域 jsonp缺点
-
项目后端做了啥
-
异步并行/串行
问 异步事情1、异步事情2是并行仍是串行?怎样变为并行?async() { await 异步事情1 await 异步事情2 }
这儿我说的是让异步事情不写在
await
后边,这是一种完结办法。当然还有更好的完结办法,所以面试官问了下一题。async ()=>{ let result1 = 异步事情1 let result2 = 异步事情2 let res1 = await result1 let res2 = await result2 console.log(res1,res2) }
-
promose.all 和 promise.allSettled
先说怎样用
promise.all
处理上一题吧async ()=>{ var result = await Promise.all([异步事情1,异步事情2]) console.log(result[0],result[1]) }
这么写的确能够处理上题的问题,可是在
promise.all
中假如有一个异步事情犯错,那么将会回来一个失败的promise
。所以假如异步事情互不依靠的话运用promise.allSettled
可能会更好,不管每个异步事情履行成功或失败都会回来一个带有履行成果的promise
。
> 想了解更多更多promise.allSettled
能够看这儿~async ()=>{ var result = await promise.allSettled([异步事情1,异步事情2]) console.log(result[0],result[1]) }
最终
以上便是莉莉丝、哈啰、滴滴的面试共享啦!都是一面的问题,二面问的首要是项目和算法所以就没发了。
关于前端面试的常考题也在上一篇文章做了共享:[2022]最新前端高频面试题总结(一)
关于其他公司的面经咱们有爱好能够到我的仓库看看:面经 鱼丸仙仙/2022-面试题总结
最终期望我和正在看文章的你都能拿到心仪的offer~ 冲冲冲