模拟面试、简历指导、入职指导、项目指导、答疑解惑 可私信找我~已帮助100+名同学完成改造!
前言
大家好,我是林三心,用最通俗易懂的话讲最难的知识点是我的座右铭,基础是进阶的前提是我的初心~
题目
一面
1、['10', '10', '10', '10', '10'].map(parseInt) 的输出值是什么?
2、你们现在的技术栈是什么?为什么要使用ts?
3、setTimeout的执行过程(事件循环,同步、异步)?
4、对Promise的理解,与async、await的区别,async、await是怎么实现的?
5、解释 requestAnimationFrame/requestIdleCallback,分别有什么用?
6、react性能优化?
7、说说对flex的理解?
8、回流、重绘是什么?如何减少回流和重绘?
10、怎么寻找react页面卡顿的原因?
11、编程题:实现一个对象的 flatten 方法,如下:
const obj = { a: { b: 1, c: 2, d: { e: 5 } }, b: [1, 3, {a: 2, b: 3}], c: 3 }
flatten(obj){} 结果返回如下:
// { // 'a.b': 1, // 'a.c': 2, // 'a.d.e': 5, // 'b[0]': 1, // 'b[1]': 3, // 'b[2].a': 2, // 'b[2].b': 3 // c: 3 // }
二面
1、说说对web worker的理解
2、service worker和强缓存相比,有哪些优势?
3、说说对堆栈溢出的理解
4、position中的sticky是什么,还有哪些其他的?
5、ts中,any和unknown分别是什么意思?泛型怎么使用?
6、bind有什么用?连续多个bind,最后this指向是什么?
7、webpack的plugin怎么实现?
8、编程题:现已知一个字符串是由正整数和加减乘除四个运算符(+ - * /)组成。例如存在字符串 const str = '11+2-3 4+5/2 4+10/5',现在需要将高优先级运算,用小括号包裹起来,例如结果为 '11+2-(3 4)+(5/2 4)+(10/5)'。注意可能会出现连续的乘除运算,需要包裹到一起。请用 javascript 实现这一过程
三面
1、手写体:使用TypeScript 实现一个 get 函数来获取它的属性值
const data = { name: 'tom', age: 18, address: 'xxx' }
2、ts中的 any 、 unknown 的区别
3、有用过ts中的 keyof 吗?
4、for in/for of的区别?
5、Promise值穿透?
解答
一面
1、['10', '10', '10', '10', '10'].map(parseInt) 的输出值是什么?
可转化为:
['10', '10', '10', '10', '10'].map((num, index) =>parseInt(num, index))
// [10, NaN, 2, 3, 4]
'10'0 -> 10: 进制为0,则默认10进制
'10'1 -> NaN: 1进制不存在
'10'2 -> 2: 2 * 1 + 2 * 0
'10'3 -> 3: 3 * 1 + 3 * 0
'10'4 -> 4: 4 * 1 + 4 * 0
2、你们现在的技术栈是什么?为什么要使用ts?
typescript
是
JavaScript
的超集,它本质其实是是在
JavaScript
上添加了
可选静态类型
和
基于类的面向对象编程
typescript 的特点
可以在编译期间发现并纠正错误
提高可维护性
提高协同开发的效率
支持强类型、接口、泛型、模块
3、setTimeout的执行过程(事件循环,同步、异步)?
事件循环
1、执行同步代码
2、
1
中生成的
微任务
先执行
3、
1
中生产的
宏任务
再执行
同步
简单来说就是:排队。代码有前后顺序,必须按照顺序去执行 异步
异步任务可以不阻塞后面的代码执行,而是可以同时进行,并且执行完后会有一个异步的回调。
想起一个故事可以很好的解释
同步
和
异步
同步:你打电话去书店借书,老板接电话时让你等着,他去找书,你只能守着电话干等着
异步:你打电话去书店借书,老板接电话后说等他找到书再打回给你,然后挂电话了,这段找书的时间你可以自由活动
4、对Promise的理解,与async、await的区别,async、await是怎么实现的?
Promise的理解
顾名思义,
Promise
就是
承诺
的意思,表现在了Promise的状态一旦改变则不会再变了,如果状态为
fulfilled
则执行
then
,如果状态为
rejected
则执行
catch
,Promise 也支持
链式调用
。我觉得Promise最大的用处就是
解决了回调地狱,提高了代码的可读性
。常用的方法有
resolve、reject、then、catch、race、all、allSettled、any、finally
async await
async/await
的作用是
用同步的方式执行异步的操作
,它的实现原理,我个人理解就是利用了
Promise
的不断嵌套,再加上
generator函数
的步骤控制,实现了按顺序执行异步操作的效果
补充:async函数返回的是一个Promise
5、解释 requestAnimationFrame/requestIdleCallback,分别有什么用?
requestAnimationFrame:
一般间隔是
16ms
,因为大部分电脑都是 每秒60帧 ,所以
1000 / 60 ≈ 16ms
会把每一帧中的所有DOM操作集中起来,在一次重绘或回流中完成,且时间间隔紧紧跟随浏览器的刷新频率
如果有隐藏或不可见的元素,将不会进行重绘或回流,减少了cpu、gpu的内存使用量
如需取消则使用
cancelAnimationFrame
requestIdleCallback:我的理解就是找浏览器空闲时间去执行传入的回调,具体也没在项目中使用过
6、react性能优化?
7、说说对flex的理解?
弹性布局
,设置了
display: flex
的盒子为
弹性盒子
,子元素会自动变成
弹性项目
,盒子有一根主轴,默认是水平,并且有一个交叉轴(跟主轴垂直)。
弹性盒子的样式:
flex-direction:定义主轴方向
flex-wrap:是否允许换行
flex-flow:flex-direction 和 flex-wrap的简写
justify-content:主轴方向上的对齐方式
align-items:交叉轴方向的对齐方式
align-content:多根轴线的对齐方式
弹性项目的样式:
order:定义项目的排列顺序,数值越小排列越靠前,默认0
flex-grow:定义项目的放大比例,默认为
0
flex-shrink:定义项目的缩小比例,默认为1
flex-basis:定义了在分配多余空间之前,项目占据的主轴空间,默认auto
flex:flex-grow、flex-shrink、flex-basis的简写
align-self:允许单个项目设置不同的交叉轴对齐方式
8、回流、重绘是什么?如何减少回流和重绘?
重绘回流
回流:尺寸、布局改变时,引起页面重新构建
重绘:元素外观、风格改变时,不影响布局,则为重绘
区别:回流一定引起重绘,重绘不一定引起回流
浏览器帮忙:浏览器维护一个队列,把所有引起回流、重绘的操作放入这个队列,等队列到了一定数量或者到了一定的时间间隔,浏览器就会清空队列,进行批量处理。
避免重绘、回流
1、批量修改DOM或者样式
2、复杂动画使用绝对定位让它脱离文档流,不然会影响父元素或后续元素的频繁回流
3、GPU加速:transform、opacity、filters、will-change等样式
9、判断一个对象是数组的方法?
Object.prototype.toString.call(xxx)
Array.isArray(xxx)
xxx instaceOf Array
10、怎么寻找react页面卡顿的原因?
11、编程题:实现一个对象的 flatten 方法,如下:
const obj = { a: { b: 1, c: 2, d: { e: 5 } }, b: [1, 3, {a: 2, b: 3}], c: 3 }
flatten(obj){} 结果返回如下:
// { // 'a.b': 1, // 'a.c': 2, // 'a.d.e': 5, // 'b[0]': 1, // 'b[1]': 3, // 'b[2].a': 2, // 'b[2].b': 3 // c: 3 // }
解题
const isObject = (target) => {
returntypeof target === 'object' && target !== null
}
const flatten = (obj) => {
if (!isObject) return
const res = {}
const dfs = (cur, prefix) => {
if (isObject(cur)) {
if (Array.isArray(cur)) {
cur.forEach((item, index) => dfs(item, `${prefix}[${index}]`))
} else {
for(let key in cur) {
dfs(cur[key], `${prefix}${prefix ? '.' : ''}${key}`)
}
}
} else {
res[prefix] = cur
}
}
dfs(obj, '')
return res
}
二面
1、说说对web worker的理解
1、开启一个子线程,并在此子线程进行一些大数据处理或者耗时的操作
2、使用
postMessage
和
onmessage
,实现主线程和子线程之间的通信
3、使用
onerror
监听子线程挂了没
4、
web worker
并没有改变JavaScript单线程的事实
2、service worker和强缓存相比,有哪些优势?
service缓存没用过。。
3、说说对堆栈溢出的理解?
常见的情况发生在
大数量递归
或
死循环
时,就会造成
栈溢出
,因为每次执行代码都需要分配一定空间的内存,以上两种情况都会使执行空间超出最大限度,从而报错
4、position中的sticky是什么,还有哪些其他的?
static:默认
relative:相对定位,相对于自身定位
absolute:绝对定位,相对于非static的第一个祖宗元素定位
fixed:相对于浏览器窗口进行定位
inherit:规定应该从父元素继承 position 属性的值
sticky:吸顶定位
5、ts中,any和unknown分别是什么意思?泛型怎么使用?
any:变量如果是 any 类型,绕过所有类型检查,直接可使用
unknown:变量如果是 unknow 类型,需要判断完是什么类型之后才能使用
6、bind有什么用?连续多个bind,最后this指向是什么?
bind
的作用是改变函数执行的指向,且不会立即执行,而是返回一个新的函数,可以自主调用这个函数的执行(此函数不可当做构造函数)
连续多个bind之后this指向始终指向第一个
7、webpack的plugin怎么实现?
一个plugin就是一个类,类里有一个
apply方法
,每次打包时都会调用这个apply,而这个apply方法接受一个参数对象,其中有一个
plugin
方法,此方法中有许多
钩子函数
,且可以决定静态文件的生成,修改等等
8、编程题:
现已知一个字符串是由正整数和加减乘除四个运算符(+ - * /)组成。例如存在字符串 const str = '11+2-3 4+5/2 4+10/5',现在需要将高优先级运算,用小括号包裹起来,例如结果为 '11+2-(3 4)+(5/2 4)+(10/5)'。注意可能会出现连续的乘除运算,需要包裹到一起。请用 javascript 实现这一过程
解答 我比较菜,用的方法也是临时想出来的,没有优化,大家将就着看吧:
const checkType = (str) => {
if (['*', '/'].includes(str)) return'high'
if (['+', '-'].includes(str)) return'low'
return'number'
}
const addBrackets = (formula) => {
const strs = formula.split('')
let i = 0, j = 1, high = false, res = []
while(j < strs.length) {
const jType = checkType(strs[j])
if (jType === 'low' && !high) {
i = ++j
j++
}elseif (jType === 'low' && high) {
res.push(j++)
i = j++
high = false
}elseif (jType === 'high') {
j++
!high && res.push(i)
high = true
}else {
j++
}
}
if (high) res.push(strs.length)
let add = 0
for(let i = 0; i < res.length; i++) {
const index = res[i]
strs.splice(index + add, 0, add % 2 ? ')' : '(')
add++
}
return strs.join('')
}
三面
1、手写体:使用TypeScript 实现一个 get 函数来获取它的属性值
const data = { name: 'tom', age: 18, address: 'xxx' }
解答:
constget = <T extends object, K extends keyof T>(obj: T, key: K): T[K] => {
return obj[key]
}
2、ts中的 any 、 unknown 的区别?
any:变量如果是 any 类型,绕过所有类型检查,直接可使用
unknown:变量如果是 unknow 类型,需要判断完是什么类型之后才能使用
3、有用过ts中的 keyof 吗?
将一个interface的所有key,汇聚成一个联合类型,可以用来对传入key的限制,比如:
interface Target {
name: string,
age: number
}
const fn = (obj: Target, key: keyof Target) => {}
const obj: Target = { name: 'sunshine', age: 18 }
fn(obj, name) // 成功
fn(obj, age) // 成功
fn(obj, height) // 报错
4、for in/for of的区别?
for in:遍历对象的key或者数组的索引
for of:遍历可迭代对象的值,如数组、Set
5、Promise值穿透
then或catch没有传入函数的话,会发生值穿透,原理是Promise内部检测如果传入的是非函数,则会拿上一次的结果包装成一个返回Promise的函数,达到穿透效果
例如:
Promise.resolve('foo')
.then(Promise.resolve('bar'))
.then(function(result){
console.log(result) // foo
})
但是如果传入的是函数的话:
Promise.resolve('foo')
.then(() =>Promise.resolve('bar'))
.then(function(result){
console.log(result) // bar
})
结语
我是林三心
一个待过 小型toG型外包公司、大型外包公司、小公司、潜力型创业公司、大公司 的作死型前端选手;
一个偏前端的全干工程师;
一个不正经的掘金作者;
逗比的B站up主;
不帅的小红书博主;
喜欢打铁的篮球菜鸟;
喜欢历史的乏味少年;
喜欢rap的五音不全弱鸡如果你想一起学习前端,一起摸鱼,一起研究简历优化,一起研究面试进步,一起交流历史音乐篮球rap,可以来俺的摸鱼学习群哈哈,点这个,有7000多名前端小伙伴在等着一起学习哦 --> 摸鱼沸点
广州的兄弟可以约饭哦,或者约球~我负责打铁,你负责进球,谢谢~