金三银四,前端面试不完全总结

金三银四,前端面试不完全总结

金三银四的季节又来了,笔者一直在武汉工作,年前裸辞后,过完年一共面了接近两个星期,有阿里,腾讯,金山,万科,趣头条等公司,在武汉拿到了4个offer(金山、万科、航班管家、财人汇)后,又在深圳一站式面了腾讯,那当然是去腾讯啦,哈哈哈哈,这里不完全记录一点面试中遇到的问题

直接导入的格式有点问题,原地址(有用的话可以给个start噢):

https://github.com/linpenghui958/note/blob/master/2019%E9%9D%A2%E8%AF%95.mdgithub.com

面试不完全汇总linpenghui958/note面试不完全汇总

float和flex的区别

为什么会有flex

了解CI CD吗

React和Vue的差异

移动端高清问题

移动端点击穿透问题

Nodejs的模块化和ES6的模块化区别

http的优缺点

restful和graphQL优缺点,对比

事件委托的优缺点

何时需要用到border-box

csrf是什么,如何用预防

fastclik的作用

前端性能优化

CSS居中+等比宽高问题

margin-top/margin-bottom百分数问题

TCP和UDP区别

float和flex的区别

float 脱离文档流 布局的传统解决方案,基于盒状模型,依赖 display 属性 + position属性 + float属性。它对于那些特殊布局非常不方便,比如,垂直居中就不容易实现。 缺点: - 容错性差,耦合度高,其中一个浮动元素出现问题,其他也会受影响 - 必须要有固定的布局 - 低版本IE不兼容

flex W3C 提出了一种新的方案----Flex 布局,可以简便、完整、响应式地实现各种页面布局 flex性能改进在于, - 相比传统margin,可伸缩性强(不算性能) - 相比float,关联性重绘好很多 - 相比tranform,子元素和父元素样式控制操作更少

RESTful优缺点 特点:充分利用 HTTP 协议本身语义。 无状态,这点非常重要。在调用一个接口(访问、操作资源)的时候,可以不用考虑上下文,不用考虑当前状态,极大的降低了复杂度。 HTTP 本身提供了丰富的内容协商手段,无论是缓存,还是资源修改的乐观并发控制,都可以以业务无关的中间件来实现。

React和Vue的差异

相似处 Virtual DOM、组件化、Props 差异 1. 渲染优化,是否需要用shouldComponentUpdate,PureComponent 2. JSX 和 Template , CSS in JS 3. Vue-cli 和 create-react-app 4. 学习难度,学 React 前,你需要知道 JSX 和 ES2015

移动端高清问题

  • DPR (device pixel ratio)= device pixel(设备像素) \ CSS pixel(css像素)
  • 1px解决方案
    • border-image 、 background-image 缺点:修改颜色麻烦,圆角需要特殊处理
    • box-shadow 缺点:在Safari下不支持小数设置
    • 伪类 + transform
    • SVG
    • viewport + rem


移动端点击穿透问题

场景:上层元素A绑定了tap事件,下层元素B绑定了click事件。当我们点击A时,A元素隐藏,此时也会触发下层B元素的click事件。 原因就是当上层A的tap事件发生后,其实是touchend结束后,会触发click事件,因为这几个事件的触发顺序是touchstart-touchmove-touchend-click。因此当click事件触发300ms后,上面的A元素已经消失,此时真正点击的就相当于下层的B元素,因此会发生点击穿透事件。 解决方案 - 都使用click或者tap - 在click事件触发前阻止,在touchend事件中使用e.preventDefault() - 使用fast-click。fastclick是一个专门解决300ms点击延迟的库。

FastClick实现原理 在document.body绑定touchstart和touchend事件 touchstart 用于记录当前点击的元素的targetElement touchend - 阻止默认事件(屏蔽之后的click事件) - 合成click事件,并添加可跟踪属性forwardedTouchEvent - 在targetElement上触发click事件 - targetElement上绑定的事件立即执行,完成FastClick

CommonJS的模块化和ES6的模块化区别

CommonJS主要依赖module、exports、require、global这几个环境变量。 CommonJS用同步方式加载模块。 ES6 module的模块不是对象,import命令会被JS引擎动态分析,在编译时就引入模块代码,而不是在代码运行时加载,所以无法实现条件加载。(ps: 也正是因为这个,使得静态分析成为可能) 差异 1. CommonJS模块输出的是一个值的拷贝,ES6模块输出的是值的引用 - CommonJS模块输出值的拷贝,一旦输出一个值,模块内部的变化就影响不到这个值。 - ES6模块的运行机制与CommonJS不一样。JS引擎对脚本静态分析的时候,遇到模块加载命令import,就会生产一个只读引用。等到脚本真正执行时,再根据只读引用,到被加载的模块中取值。原始值变了,import加载的值也会跟着变。因此ES6模块是动态引用,并且不会缓存值,模块里的变量绑定其所在的模块。 2. CommonJS模块是运行时加载,ES6模块是编译时输出接口 - 运行时加载:CommonJS模块就是对象,即在输入时先加载整个模块,生产一个对象,然后再从这个对象上面读取方法,这种加载成为”运行时加载“ - 编译时加载:ES6模块不是对象,而是通过export命令显示指定输出的代码,import时采用静态命令的形式。即在import时可以指定加载某个输出值,而不是加载整个模块,这种加载成为编译时加载 CommonJS 加载的是一个对象(即module.exports属性),该对象只有在脚本运行完才会生成。而 ES6 模块不是对象,它的对外接口只是一种静态定义,在代码静态解析阶段就会生成。

RESTful优缺点

优点: 1. 轻量,直接基于http,不需要任何别的消息协议。get/post/put/delete为CURD操作 2. 面向资源,一目了然,具有自解释性 3. 数据描述简单,一般是xml,json做数据交换

缺点: 一个适用于简单操作的接口规范,复杂操作并不适用,适合CRUD并且只适合CRUD,有的浏览器可能不支持POST、GET以外的操作,要特殊处理。 ps: 多个接口,更新订单收款状态、更新订单支付状态、更新订单结算状态。批量操作,get超出长度

  1. 客户端-服务器:提供服务的服务器和使用服务的客户端分离解耦
  • 提高客户端的便捷性(操作简单)
  • 简化服务器提高可伸缩性(高性能、低成本)
  • 允许客户端服务端分组优化不受影响
  • 无状态:来自客户的每一个请求必须包含服务器处理该请求所需的所有信息(请求信息唯一性)
  • 提高了可见性(可以考虑每个请求)
  • 提高了可靠性(更容易故障恢复)
  • 提高了可扩展性(降低了服务器资源使用)
  • 可缓存:服务器必须让客户端知道请求是否可以被缓存?如果可以,客户端可以重用之前的请求信息发送请求
  • 减少交互连接数
  • 减少链接过程的网络延迟
  • 分层系统:允许服务器和客户端之前的中间层(代理,网关等)代替服务器对客户端的请求进行回应,而客户端不需要关心与它交互的组件之外的事情
  • 提高了系统的可扩展性
  • 简化了系统的复杂性
  • 统一接口:客户和服务器之前通信的方法必须是统一的。
    提高交互的可见性 鼓励单独优化改善组件
  • 支持按需代码:服务器可以提供一些代码或者脚本并在客户的运行环境中执行
  • 提高了可扩展性

事件委托的优缺点

优点: 1. 节省内存,减少事件注册。 2. 适合动态内容

确定: 1. 如果把所有事件都是用事件代理,可能会出现误判。即本不该被触发的事件被绑定上了事件。 2. 基于冒泡,对于不冒泡的事件不支持。 3. 层次过多时,可能会被某曾组织掉。

CSRF

特点 - CSRF通常发生在第三方域名 - CSRF攻击者不能获取到Cookie等信息,只是使用。

防御策略 - 阻止不明外域的访问 - 同源监测 - Samesite cookie

  • 提交时要求附加本域下才能获取的信息
  • CSRF TOken
  • 双重Cookie验证
  • 提交验证码

为什么用transform居中而不是marginLeft/Top

浏览器渲染过程

解析DOM Tree,创建一个或多个渲染层(layer) 将每个层独立的绘进位图中(计算样式->布局->栅格化) 将层作为纹理(texture)上传至GPU 复合(composite)多个层来生成最终的屏幕图像 每个层的样式出现调整后,要重新计算样式->重新布局->重新栅格化->重新组合

使用top/left只会创建一个层,而是用transform会使浏览器将元素单独提取放在GPU单独的渲染层中,这样有三点好处: 1. 该元素任何合成属性(Composite Property)的变化将不会影响原有文档,不会导致文档被重新布局(重绘、回流) 2. 该层将由GPU负责渲染,从而节省CPU资源,不会阻塞主线程JS代码的执行 3. 动画更为平顺,这是因为使用transform可以小于像素的单位进行绘制 可能带来的负作用是额外的渲染层导致更多的线程间通信,如果过度使用,导致生成成百上千的渲染层,那反而会导致组合各层图像的成本迅速上升成为主要矛盾,且我们需要记住GPU也是有内存限制的。

使用css设置rem

使用calc(100vw / 屏幕宽度)

javascript [] == ![] 这个要牵涉到 JavaScript 中不同类型 == 比较的规则, 具体是由相关标准定义的. ![] 的值是 false, 此时表达式变为 [] == false, 参照标准, 该比较变成了 [] == ToNumber(false), 即 [] == 0. 这个时候又变成了 ToPrimitive([]) == 0, 即 '' == 0, 接下来就是比较 ToNumber('') == 0, 也就是 0 == 0, 最终结果为 true.

CSS居中 + 宽高等比变化

  1. font-size em-square
  2. line-height 实际占地高度
  3. 100px 100px -> 103px
  4. vertical top middle bottom text-top text-bottom
  5. 图片下面有空隙
  6. vertical-align top
  7. img{display: block}
  8. font-size 0 傻逼才用
  9. inline-block 元素对不齐 无解 用 flex或float
  10. inline-block 有空隙 用 flex 或 float

css垂直居中对齐

<main>
  <span>Center me, please!</span>
</main>
  1. display: flex + margin: auto
main{
        width: 100%;
        min-height: 152px;
        display: flex;
    }
    main > span {
        margin: auto;
    }
  1. display: flex , grid
main{
    width: 100%;
    min-height: 152px;
    display: grid;
    justify-content: center;
    align-items: center;
  }
  main > span {
    background: #b4a078;
    color: white;
    padding: .3em 1em .5em;
    border-radius: 3px;
    box-shadow: 0 0 .5em #b4a078;
  }
  ```
3. position: absolute + calc()
```css
  main{
    width: 100%;
    min-height: 152px;
    display: flex;
  }
  main > span {
    position: absolute;
    top: calc(50% - 16px); 
    left: calc(50% - 72px);
  }
  ```
4. position: absolute + translate
```css
  main{
    width: 100%;
    min-height: 152px;
    display: flex;
  }
  main > span {
    position: absolute;
    top: 50%; left: 50%;
    transform: translate(-50%, -50%);
  }
          ```
5. display: table / table-cell + vertical-align: middle
```css
  main {
    width: 100%;
    height: 152px;
    display: table;
  }
  main > div {
    display: table-cell;
    text-align: center;
    vertical-align: middle;
  }
  1. 伪元素 :after + vertical-align: middle
main {
    width: 100%;
    height: 152px;
    text-align: center;
  }
  main::after {
    content:'';
    display: inline-block;
    height: 100%;
    vertical-align: middle;
  }

宽高等比用css如何实现

  1. 使用隐藏图片 完美兼容PC端、移动端 如果div容器不给高度,它的高度会随容器内部元素的变化而撑大 在容器内添加一张等比宽高的图片,给图片设置宽度100% 高度auto
<style>
     #container {
       width: 100%;
     }
     .attr {
       background-color: #008b57;
     }
     .attr img{
       width: 100%;
       height: auto;
     }
     </style>
    <div id='container'>
      <div class='attr'>
        <img src="1.png" alt="">
      </div>
    </div>

还可以用base64优化

  1. 使用vmin 将父容器的宽度和高度定义为相同vmin,这样父容器宽高就是相同值,然后给子容器宽高设置百分比
  2. vw 相对于视窗的宽度
  3. vh 相对于视窗的高度
  4. vmin 相对于视口的宽度或高度中较小的那个被均分为100单位的vmin
  5. vmax 相对于视口的宽度或高度中较大的那个被均分为100单位的vmax
#container{
  width: 100vmin;
  height: 100vmin;
  }

.attr {
  width: 50%;
  height: 50%;
  background-color: orange;
}
  1. 使用scale
.attr{
  width:50%;
  height: calc(50%);
}
  1. padding-top/padding-bottom 实现 因为padding-bottom的属性值百分比是按照父容器的宽度来计算。
<style type="text/css">
    #container {
        width: 80%;
        height: 500px;
    }

    .attr {
        width: 50%;
        height: 0;
        padding-bottom: 50%;
        background-color: #008b57;
    }
    </style>

    <div id='container'>
        <div class='attr'></div>
    </div>

为什么margin-top/margin-bottom的百分数也是相对于width而不是height呢?

CSS权威指南中的解释:

我们认为,正常流中的大多数元素都会足够高以包含其后代元素(包括外边距),如果一个元素的上下外边距时父元素的height的百分数,就可能导致一个无限循环,父元素的height会增加,以适应后代元素上下外边距的增加,而相应的,上下外边距因为父元素height的增加也会增加,如果循环。

UDP和TCP

UDP

简介:UDP是面向无连接的,UDP只是数据报文的搬运工,不保证有序且不丢失的传递,UDP协议没有控制流量算法,相比TCP更加轻量

面向无连接

UDP不需要和TCP一样在发送数据前进行三次握手建立连接。 并且只是数据报文的搬运工,不会对数据报文进行任何拆分和拼接。 具体来说: - 在发送端,应用层的数据 -> 传输层UDP协议,UDP只会给数据增加一个UDP头标识 - 在接收端,网络层将数据传给传输层,UDP也只去除IP报文头,就传给应用层

不可靠性

首先不可靠性体现在无连接上,通信都不需要建立连接,想发就发,这样的情况肯定不可靠。 网络不佳的情况下,UDP因为没有拥塞控制,一直会以恒定的速度发送数据。弊端就是网络不好会丢包,优点就是在某些时效性要求高的场景适合。

高效

UDP的头部开销小,只有八个字节(TCP至少二十字节) UDP头部包含以下几个数据: - 两个十六位端口号,分别为源端口和目标端口 - 整个数据报文的长度 - 整个数据报文的检验

传输方式

UDP支持一对一,一对多,多对多,多对一,也就是单播,多播,广播

适用场景

  • 直播
  • 游戏

TCP

建立和断开连接都要进行握手。在传输过程中,通过各种算法保证数据的可靠性。 相对UDP来说不那么的高效。

头部

  • Sequence number,这个序号保证了TCP传输的报文是有序的,对端可以通过序号顺序拼接报文
  • Acknowledgement number,这个序号表示数据接收端 期望接受的下一个字节的编号是多少,同时也表示上一个序号的数据已经收到
  • Window Size,窗口大小,表示还能接受多少字节的数据,用于流量控制
  • 标识符

状态机

  • 建立连接三次握手 不管是客户端还是服务端,TCP 连接建立完后都能发送和接收数据,所以 TCP 是一个全双工的协议。

第一次握手

客户端向服务端发送连接请求报文段。该报文段中包含自身的数据通讯初始序号。请求发送后,客户端便进入 SYN-SENT 状态。

第二次握手

服务端收到连接请求报文段后,如果同意连接,则会发送一个应答,该应答中也会包含自身的数据通讯初始序列号,发送完成后便进入SYN-RECEIVED状态。

第三次握手

当客户端收到连接同意的应答后,还要向服务端发送一个确认报文。 客户端发完这个报文段便进入ESTABLISHED状态。 服务端发完这个应答后也会进入ESTABLISHED状态。

ps: 为什么 TCP 建立连接需要三次握手,明明两次就可以建立起连接 因为这是为了防止出现失效的连接请求报文段被服务端接收的情况,从而产生错误。

断开连接四次握手

  • 第一次握手 若客户端 A 认为数据发送完成,则它需要向服务端 B 发送连接释放请求。
  • 第二次握手 B 收到连接释放请求后,会告诉应用层要释放 TCP 链接。然后会发送 ACK 包,并进入 CLOSE_WAIT 状态,此时表明 A 到 B 的连接已经释放,不再接收 A 发的数据了。但是因为 TCP 连接是双向的,所以 B 仍旧可以发送数据给 A。
  • 第三次握手 B 如果此时还有没发完的数据会继续发送,完毕后会向 A 发送连接释放请求,然后 B 便进入 LAST-ACK 状态。
  • 第四次握手 A 收到释放请求后,向 B 发送确认应答,此时 A 进入 TIME-WAIT 状态。该状态会持续 2MSL(最大段生存期,指报文段在网络中生存的时间,超时会被抛弃) 时间,若该时间段内没有 B 的重发请求的话,就进入 CLOSED 状态。当 B 收到确认应答后,也便进入 CLOSED 状态。 ps: 2MSL 为了保证 B 能收到 A 的确认应答。若 A 发完确认应答后直接进入 CLOSED 状态,如果确认应答因为网络问题一直没有到达,那么会造成 B 不能正常关闭。

ARQ协议

ARQ协议就是超时重传机制。通过确认和超时机制保证数据的正确送达。 ARQ协议包含停止等待ARQ连续ARQ两种协议。

编辑于 2019-03-30

文章被以下专栏收录