前言

明天给大家分享一个字节跳动系公司——石墨文档的面经吧!废话不多说,先看题目!

题目

一面

  • 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 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) => {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的题目

我是林三心,一个热心的前端菜鸟程序员。如果你上进,喜爱前端,想学习前端,那咱们能够交朋友,一起摸鱼哈哈,摸鱼群,加我请备注【思否】