前言
明天给大家分享一个字节跳动系公司——石墨文档的面经吧!废话不多说,先看题目!
题目
一面
- 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-34+5/24+10/5',当初须要将高优先级运算,用小括号包裹起来,例如后果为 '11+2-(34)+(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 awaitasync/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) => {return typeof target === 'object' && target !== null}const flatten = (obj) => {if (!isObject) returnconst 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-34+5/24+10/5',当初须要将高优先级运算,用小括号包裹起来,例如后果为 '11+2-(34)+(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++ }else if (jType === 'low' && high) { res.push(j++) i = j++ high = false }else if (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' }
解答:
const get = <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 })
结语
因为自己React太菜,所以不敢答题无关React的题目
我是林三心,一个热心的前端菜鸟程序员。如果你上进,喜爱前端,想学习前端,那咱们能够交朋友,一起摸鱼哈哈,摸鱼群,加我请备注【思否】