前端高频面试题(附答案)

292 阅读9分钟

网络相关

TCPUDP 的区别

- TCP UDP
是否连接 面向连接 无连接
是否可靠 可靠,使用流量控制和拥塞控制 不可靠,不使用流量控制和拥塞控制
连接对象个数 只能是一对一 可以一对一,一对多,多对多交互通信
传输报文 面对字节流 面向报文
首部开销 最小20字节,最大60字节 仅8字节
适用场景 适用于要求可靠传输的场景 实时应用(直播,IP电话,视频会议等)

TCP 连接的三次握手和断开连接的四次挥手

三次握手的动态过程

  1. 客户端首先向服务器端发送一段 TCP 报文,表示发起连接请求
  • 标记位为 SYN ,表示“请求建立新连接”;
  • 序号为 Seq=X (X一般为1);
  • 随后客户端进入 SYN-SENT 阶段。
  1. 服务器端接收到 TCP 报文之后,结束 LISTEN 阶段,并返回一段 TCP 报文
  • 标志位为 SYNACK ,表示“确认客户端的报文 Seq 序号有效,服务器能正常接收客户端发送的数据,并同意创建新连接”(即告诉客户端,服务器收到了你的数据);
  • 序号为 Seq=y
  • 确认号为 Ack=x+1 ,表示收到客户端的序号 Seq 并将其值加1作为自己确认号 Ack 的值;随后服务器端进入 SYN-RCVD 阶段。
  1. 客户端收到服务器端确认收到数据的 TCP 报文之后,结束 SYN-SENT 阶段。并返回最后一段 TCP 报文
  • 标志位为 ACK ,表示“确认收到服务器端同意连接的信号”(即告诉服务器,我知道你收到我发的数据了);
  • 序号为 Seq=x+1 ,表示收到服务器端的确认号 Ack ,并将其值作为自己的序号值;
  • 确认号为 Ack=y+1 ,表示收到服务器端序号 Seq ,并将其值加1作为自己的确认号 Ack 的值;
  • 随后客户端进入 ESTABLISHED 阶段。

服务器收到来自客户端的“确认收到服务器数据”的 TCP 报文之后,明确了从服务器到客户端的数据传输是正常的。结束 SYN-SENT 阶段,进入 ESTABLISHED 阶段。

断开连接的四次挥手

  1. 首先客户端想要释放连接,向服务器端发送一段 TCP 报文,表示请求释放连接
  2. 服务器端接收到客户端的 TCP 报文之后,确认了客户端想要释放连接,随后服务器端结束 ESTABLISHED 阶段,进入 CLOSE-WAIT 阶段(半关闭状态)并返回一段 TCP 报文,表示接收到客户端释放连接的请求,并准备开始释放连接
  3. 当服务器做好了释放连接的准备之后,再向客户端发送一段 TCP 报文,此时结束 CLOSE-WAIT 阶段,进入 LAST-ACK 阶段,并且停止服务器端->客户端发送数据,但仍能够接收到客户端传输过来的数据
  4. 客户端收到服务器端发出的 TCP 报文之后,确认了服务器端已经做好释放连接的准备,结束 FIN-WAIT-2 阶段,进入 TIME-WAIT 阶段,并向服务器端发送一段报文,随后客户端在 TIME-WAIT 阶段等待 2MSL

服务端接收到从客户端发出的 TCP 报文之后,结束 LAST-ACK 阶段,进入 CLOSED 阶段,此时正式关闭服务器到客户端方向的连接;客户端等待完 2MSL 之后,结束 TIME-WAIT 阶段,进入 CLOSED 阶段,完成四次挥手。

HTTPHTTPS 的区别

HTTP

  1. 无状态:协议对客户端没有状态存储,例如访问一个网站需要反复进行操作
  2. 无连接:每次请求都需要通过 TCP 的三次握手和四次挥手,耗费不必要的时间和流量
  3. 基于请求和响应:基本的特性,有客户端发起请求,服务端响应
  4. 简单快速,灵活
  5. 使用明文通信,无法确保数据的完整性

HTTPS(基于HTTP协议,通过SSL或TLS提供加密处理数据、验证对方身份以及数据完整性保护)

  1. 内容加密:采用混合加密技术(非对称加密和对称加密),中间者无法直接查看明文内容
  2. 验证身份:通过证书认证客户端访问的是自己的服务器
  3. 保护数据完整性:防止传输的内容被中间人冒充或者篡改

GETPOST 的区别

表面区别

  1. GET 在浏览器回退时是无害的,而 POST 会再次提交请求。

  2. GET 产生的URL地址可以被Bookmark,而 POST 不可以。

  3. GET 请求会被浏览器主动cache,而 POST 不会,除非手动设置。

  4. GET 请求只能进行url编码,而 POST 支持多种编码方式。

  5. GET 请求参数会被完整保留在浏览器历史记录里,而 POST 中的参数不会被保留。

  6. GET 方式提交数据的大小(一般来说1024字节),http 协议并没有硬性限制,而是与浏览器、服务器、操作系统有关,而 POST 理论上来说没有大小限制,http 协议规范也没有进行大小限制,但实际上 POST 所能传递的数据量根据取决于服务器的设置和内存大小。

  7. 对参数的数据类型,GET 只接受 ASCII 字符,而 POST 没有限制。

  8. GETPOST 更不安全,因为参数直接暴露在 URL 上,所以不能用来传递敏感信息。

  9. GET 参数通过 URL 传递,POST 放在 Request body 中。

重大区别

  • GET 产生一个 TCP 包,POST 产生两个

GET:浏览器会把 http header 和 data 一并发送出去,服务器响应200(返回数据)

POST:浏览器先发送 header,服务器响应100 continue,浏览器再发送 data,服务器响应200 ok(返回数据)

XSS vs CORS

- XSS CORS
含义 跨站脚本攻击 跨站脚本伪造
防范 token 存在 cookie 中,设置 httpOnly 在请求头中携带 cookie

js 相关

闭包

  • 含义:函数和对其周围状态(lexical environment,词法环境)的引用捆绑在一起构成闭包(closure)。也就是说,闭包可以让你从内部函数访问外部函数作用域。在 JavaScript 中,每当函数被创建,就会在函数生成时生成闭包。
  • 用处:闭包很有用,因为它允许将函数与其所操作的某些数据(环境)关联起来。这显然类似于面向对象编程。在面向对象编程中,对象允许我们将某些数据(对象的属性)与一个或者多个方法相关联。

因此,通常你使用只有一个方法的对象的地方,都可以使用闭包。

例如修改 fontSize 这个方法:

function makeSizer(size) {
    return function() {
        document.body.style.fontSize = size + 'px'
    }
}

const size12 = makeSizer(12)
const size16 = makeSizer(16)

原型链

  • prototype

在 JavaScript 中,每个函数都有一个 prototype 属性,该属性指向函数的原型对象。

function Person(name) {
    this.name = name
  }

Person.prototype.age = 23

const person1 = new Person()
const person2 = new Person()
console.log(person1.age)  // 23
console.log(person2.age)  // 23

上述例子中,构造函数的 prototype 指向了一个对象,而这个对象正是调用构造函数创建实例的原型,即 person1 和 person2 的原型。

原型:每一个 javaScript 对象(除 null 外)被创建的时候,就会与之关联另一个对象,这个对象就是“原型”,每一个对象都会从原型中“继承”属性。

  • __proto__

这是每个对象(除 null 外)都会有的属性,该属性指向对象的原型。

function Person() {

}
const person = new Person();
console.log(person.__proto__ === Person.prototype); // true

  • constructor

每个原型都有一个 constructor 属性,该属性指向该原型关联的构造函数。

  • 实例与原型

当读取实例的属性找不到时,就会去查找该实例的原型,如果还没有,就继续沿着 __proto__ 向上查找,一直找到最顶层为止。

  • 总结:每个构造函数都有一个原型对象,原型对象都包含一个指向构造函数的指针,而实例都包含一个指向原型对象的内部指针。那么假如我们让原型对象等于另一个类型的实例,结果会怎样?显然,此时的原型对象将包含一个指向另一个原型的指针,相应地,另一个原型中也包含着一个指向另一个构造函数的指针。假如另一个原型又是另一个类型的实例,那么上述关系依然成立。如此层层递进,就构成了实例与原型的链条。这就是所谓的原型链的基本概念。——摘自《javascript高级程序设计》

Eventloop

  • EventLoop 是一个程序结构,用于等待和发送消息和事件。 程序中设置两个线程,一个负责程序本身的运行,叫做主线程;另一个负责主线程与其他线程(主要是 IO 操作)的通信,称为 EventLoop 线程(消息线程)。 主线程开始运行,每当遇到 IO 操作,主线程就让 EventLoop 线程通知相应的 IO 程序,主线程接着往后运行,当 IO 完成之后,EventLoop 线程再把结果返回主线程。主线程调用事先设定的回调函数,完成任务。
  • MacroTask宏任务

script 全部代码、setTimeoutsetIntervalsetImmediate(浏览器暂时不支持,只有IE10支持,具体可见MDN)、I/OUI Rendering

  • MicroTask微任务

Process.nextTickNode 独有)、PromiseMutationObserver

  • 每次单个宏任务执行完毕后,检查微任务( microTask )队列是否为空,如果不为空的话,会按照先入先出的规则全部执行完微任务( microTask )后,设置微任务( microTask )队列为 null,然后再执行宏任务,如此循环。

数组去重

排序算法

  • 冒泡排序

  • 快速排序

  • 选择排序

  • 插入排序

深拷贝浅拷贝

vue

vue 的生命周期

  • 官网图解

vue 的路由模式

  • hash

hash 虽然出现 URL 中,但不会被包含在 HTTP 请求中,对后端完全没有影响,因此改变 hash 不会重新加载页面。

  • history

利用了HTML5 History Interface 中新增的 pushState()replaceState() 方法。支持传入 datatitleurl

注意:前端的url必须和实际向后端发起请求的url 一致,如 www.abc.com/book/id 。如果后端缺少对 /book/id 的路由处理,将返回 404 错误。

vue 的双向绑定原理

通俗易懂了解Vue双向绑定原理及实现

vuex 原理