1. 首页

2019高频前端面试题汇总

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

面试不完全汇总

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

    提高交互的可见性
    鼓励单独优化改善组件

  6. 支持按需代码:服务器可以提供一些代码或者脚本并在客户的运行环境中执行
    • 提高了可扩展性

事件委托的优缺点

优点:
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. 图片下面有空隙
    1. vertical-align top
    2. img{display: block}
    3. font-size 0 傻逼才用
  6. inline-block 元素对不齐 无解 用 flex或float
  7. 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,这样父容器宽高就是相同值,然后给子容器宽高设置百分比

– vw 相对于视窗的宽度
– vh 相对于视窗的高度
– vmin 相对于视口的宽度或高度中较小的那个被均分为100单位的vmin
– 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两种协议。

看完两件小事

如果你觉得这篇文章对你挺有启发,我想请你帮我两个小忙:

  1. 关注我们的 GitHub 博客,让我们成为长期关系
  2. 把这篇文章分享给你的朋友 / 交流群,让更多的人看到,一起进步,一起成长!
  3. 关注公众号 「画漫画的程序员」,公众号后台回复「资源」 免费领取我精心整理的前端进阶资源教程

JS中文网是中国领先的新一代开发者社区和专业的技术媒体,一个帮助开发者成长的社区,目前已经覆盖和服务了超过 300 万开发者,你每天都可以在这里找到技术世界的头条内容。欢迎热爱技术的你一起加入交流与学习,JS中文网的使命是帮助开发者用代码改变世界

本文著作权归作者所有,如若转载,请注明出处

转载请注明:文章转载自「 Js中文网 · 前端进阶资源教程 」https://www.javascriptc.com

标题:2019高频前端面试题汇总

链接:https://www.javascriptc.com/3138.html

« 谷歌 App Engine 支持四种新的运行时
React 初学者需要知道的一些知识»
Flutter 中文教程资源

相关推荐

QR code