一次“金三银四的前端社招面经”的解答

4,005 阅读9分钟

3月28日更新,这篇文章的内容是我随手答的,我重新整理了一份正确答案,请移步,

juejin.cn/post/694471…

-------------------------------------

3月26日更新,原答案是我个人的见解,介于这篇文章发酵比较快,这周末我会整理一份标准答案给大家。

-------------------------------------

目前前端招聘标准越来越高,上面分享的面经很具有代表性,但是只有题目没有答案,所以我就挑选了字节的1面2面,做了简单的回答,这是本人未经过加工的回答,肯定会存在纰漏,但是可供大家参考。后续会将正确的答案汇总,欢迎评论区讨论。

下面是原文链接

juejin.cn/post/693977…

1面

1、tcp 和 udp 的区别和使用场景?

原答案
tcp具有面向连接,流量控制,拥塞控制,重传机制。tcp传输过程是安全的,具有丢包重传等性质,也存在队头阻塞,每次链接需要3次握手等耗时问题,适合注重安全稳定性的场景,比如web应用。
udp不是面向连接的,因为不具备内容完整性校验和重传机制等功能,所以丢包率比tcp高,但是协议更加简单,无需多次握手,更快速,适合音视频等场景。

正确答案

参考这篇文章即可,mp.weixin.qq.com/s/lU5uPfhFE…

2、 quic 基于 udp 怎么保证可靠性?

上面说了udp不是面向链接的,而且udp传输的时候,不携带源端IP和源端口号,无法重试。需要添加源IP和端口号,并且增加序列,保证内容完整性。

3、 讲一下同源策略和跨域方案?CORS 的几个头部是什么?

浏览器为了保证资源的安全性,实施了同源策略,包括协议,域名,端口一致。

jsonp,通过script标签,src天然跨域。cors,浏览器和服务端同时设置支持跨域,cross origin resource sharing,也可以设置为单独域名,也可以设置为*。

4、 讲一下 react fiber?

fiber是纤维的意思,它是react里的一种数据结构,链表。存储了当前组件的所有信息,每一个虚拟DOM都对应一个fiber,每一个fiber通过链表相连。react进行虚拟Dom对比时,就是从根fiber开始对比。

5、 vue 双向绑定原理?

本质是一个发布订阅模式,通过Object.defineProperty或Proxy实现中间存储的转发功能。拦截数据的getter,setter操作,绑定数据,并在触发变更时触发更新。

6、 redux 和 mobx 的区别和使用场景?

它们都是状态管理框架,redux是一种流式管理框架,通过dispatch,action,reducer流程,保证状态可观测。并且只能在reducer修改数据,保证数据只在一个地方可变更。而mobx是响应式,有点像vuex,底层也是通过Proxy实现。两者都使用高阶组件的方式,改变外层的props,触发子组件的render。当然也在shouldComponentUpdate里做了一层浅比较。

7、 typeof null?null instanceof Object?

原答案
"object"truetypeof null就是js的一个错误设计。

正确答案,"object",false。null instanceof Object和typeof null都是js错误的设计。

8、typeof 可以判断哪些类型?instanceof 做了什么?

原答案
基础数据类型,除了null。基础引用类型,ObjectArrayFunction。
自定义的类或者DateRegExp等不支持。
instanceof检测当前对象是否属于后面的对象,通过原型链判断。判断原型链上的type属性?

正确答案

typeof可以判断 number、boolean、symbol、string、object、undefined、function。无法判断Date、RegExp等复杂的对象。

这是 instanceof 的用法,但是 instanceof 的原理是什么呢?根据 ECMAScript 语言规范,我梳理了一下大概的思路,然后整理了一段代码如下

其实 instanceof 主要的实现原理就是只要右边变量的 prototype 在左边变量的原型链上即可。因此,instanceof 在查找的过程中会遍历左边变量的原型链,直到找到右边变量的 prototype,如果查找失败,则会返回 false,告诉我们左边变量并非是右边变量的实例。

function new_instance_of(leftVaule, rightVaule) { 
    let rightProto = rightVaule.prototype; // 取右表达式的 prototype 值
    leftVaule = leftVaule.__proto__; // 取左表达式的__proto__值
    while (true) {
    	if (leftVaule === null) {
            return false;	
        }
        if (leftVaule === rightProto) {
            return true;	
        } 
        leftVaule = leftVaule.__proto__ 
    }
}

是来自这篇掘金文章的解释。juejin.cn/post/684490…

9、 实现一个 bind 函数

是否可以使用apply,不能用apply就只能用eval。(这个bind函数也考虑不全面,后续优化)

function bind(obj,ctx){
return (...args)=> {
  	obj.apply(ctx,args);
} 
}

bind(a, window);

10、 求数组里面最大连续项的和

[1, -2, 3, 4, -1, 5];

=> 11

function getMaxSum(arr) {
  let dp = new Array(arr.length).fill(0);

  dp[0] = arr[0];
  
  let maxSum = 0

  for (let i = 1; i < arr.length; i++) {

    dp[i] = Math.max(arr[i], dp[i -1] + arr[i]);

    if (dp[i] > maxSum) {
      maxSum = dp[i];
    }
  }

  return maxSum;
}

console.log(getMaxSum([1, -2, 3, 4, -1, 5]));

11、 event loop

event loop不同的宿主环境有不同的表现。

在浏览器里,event loop分为macro task和micro task,loop从一个宏任务开始,不断循环。如果没有异步任务,就同步执行。如果有微任务就插入当前宏任务的队尾,如果有宏任务,就插入维护宏任务的队列中。

宏任务有,脚本执行,setTimeout等函数,用户交互等,ajax,I/O。微任务有,promise,await async。mutation,intersectionObserver,postMessage等。

在node中,为了保证时间函数到点执行,每一个event loop都会先检测setTimeout,interval是否到期。以及新增nextTrick,再当前eventLoop结束时执行的回调,而当前注册的setImmdeiate事件将在下次event loop执行。

Node中执行的优先级

timers

io

check阶段,setImmediate回调

nextTrick执行阶段。

2面

1、怎么优化 h5 的加载速度?

原答案
工程和细节方向两个方向优化。
工程方向,打包内容,资源加载类型等
细节方向,熟悉浏览器特性,比如减少重绘重排。React框架,优化代码。渲染机制,懒加载(图片,资源等)。

正确答案

直接参考我之前整理过的文章,zhuanlan.zhihu.com/p/350333912

2、离线包怎么更新?怎么知道需要打开哪个离线包?

每次进入一个新页面,异步检查配置文件,是否需要更新。

通过版本号。

3、js bridge 通信原理?

以Android为例。

js bridge充当中间者的作用,让js和Android可以双向通信。Android将事件注入到前端上下文window中,有两种事件,一种是回调事件,和React生命周期相似的事件;另一种是预留给前端主动调用Android的事件。这样前端既能主动调用Android,也能注册Android的某些事件,等待回调。因为两者只能通过Json String通信,所以前端调用Android之后的回调事件,是注册到Bridge的队列中,通过自增id标识,下一个回调事件是什么。

4、怎么实现 h5 页面秒开?

离线包,懒加载,service worker。

5、明明不是同一个语言,为什么 js 和 native 可以通信?

依赖于webview这个载体,webview是存在于native的上下文(在Android中它是一个组件),而js的上下文是存在于webview。

6、怎么实现 js bridge 跨多个 app 共用?

封装成sdk。把细节抽象。

7、grpc 相比 http 的优势?

grpc,跨远程调用,只是跨进程,最多需要将数据序列化和反序列化。而http需要走网络请求。

8、rpc 的调用流程?前端怎么调用 grpc 的?

进程A的应用调用进程B的应用。我记得在vscode里,可以有专门的包支持rpc,它内部应该封装了进程间调用的细节。

9、为什么要用 grpc?

更快,心智负担更小,像调本地函数一样调用

10、服务发现为什么用 ip,而不用域名?

域名需要DNS解析。域名本来就是方便用户记忆和美观的。

11、怎么做 DNS 预解析?

请求DNS支持解析的服务器。全球有专门做DNS解析的服务器,而每个国家,每个地方又会缓存一些常用的IP和域名的映射表。电脑和浏览器为了优化打开速度,也会缓存DNS结果,所以有时候DNS更新了,但是还是访问之前的网站。

12、怎么实现移动端的布局?

可以通过百分比,rem,vw,vh等自适应方式实现布局。

13、iOS 下软键盘输入框遮挡遇到过问题么?怎么解决顶不起来的问题?

低版本IOS会出现,键盘弹起,但是输入框被遮挡的问题,可以键盘弹起事件,自定义一个滚动事件,滚到输入框的位置。

14、实现两个大数相加

之前写过,我就直接粘贴了。可以不用转成数组,直接用字符串的charAt获取单个值,这个算法注意进位carry即可。

/**
 * @param {string} num1
 * @param {string} num2
 * @return {string}
 */
var addStrings = function(num1, num2) {
  const arr1 = num1.split('').reverse();
  const arr2 = num2.split('').reverse();
  let carry = 0;
  let index = 0;
  let result = [];

  while(index + 1 <= arr1.length || index + 1 <= arr2.length) {
      let a1 = 0;
      let a2 = 0;
      if (arr1[index]) {
          a1 = arr1[index];
      }

      if (arr2[index]) {
          a2 = arr2[index];
      }

      const total = Number(a1) + Number(a2) + carry;
      if (total >= 10) {
          result.push(total - 10);
          carry = 1;
      } else {
          result.push(total);
          carry = 0;
      }

      index++;
  }

  if (carry) {
      result.push(1);
  }

  return result.reverse().join('');
};

addStrings('0', '0')

15、求一个数组最大子项的和,要求这些子项在数组中的位置不是连续的

这是LeetCode的题目,198.打家劫舍,还是利用动态规划求解,后续整理题解。

16、常用的 react hooks 方法

useState、useEffect、useMemo、useCallback、useReducer、useLayoutEffect、useRef、useContext。

17、useState 怎么做缓存的?

mount阶段将数据缓存到当前虚拟DOM的fiber上,update时,前比较两次的值。如果值未改变,还用缓存的值。这个回答好像有点问题。

18、react fiber 是什么?

1面回答过

19、怎么解决 useState 闭包的问题?

这个是问怎么解决useEffect闭包问题吧,传入依赖项即可。或者将state值赋值给useRef,这样每次useRef上的值都是最新的值。

20、useReducer 比 redux 好在哪里?

react内置支持。支持依赖项不更新,不触发useReducer的回调。更加轻量,无需引用框架,无需维护一个大的store树。