写点什么

前端必会面试题

作者:loveX001
  • 2023-02-13
    浙江
  • 本文字数:8742 字

    阅读完需:约 29 分钟

let 闭包

let 会产生临时性死区,在当前的执行上下文中,会进行变量提升,但是未被初始化,所以在执行上下文执行阶段,执行代码如果还没有执行到变量赋值,就引用此变量就会报错,此变量未初始化。

数组的遍历方法有哪些

其他值到字符串的转换规则?

  • Null 和 Undefined 类型 ,null 转换为 "null",undefined 转换为 "undefined",

  • Boolean 类型,true 转换为 "true",false 转换为 "false"。

  • Number 类型的值直接转换,不过那些极小和极大的数字会使用指数形式。

  • Symbol 类型的值直接转换,但是只允许显式强制类型转换,使用隐式强制类型转换会产生错误。

  • 对普通对象来说,除非自行定义 toString() 方法,否则会调用 toString()(Object.prototype.toString())来返回内部属性 [[Class]] 的值,如"[object Object]"。如果对象有自己的 toString() 方法,字符串化时就会调用该方法并使用其返回值。

浏览器是如何对 HTML5 的离线储存资源进行管理和加载?

  • 在线的情况下,浏览器发现 html 头部有 manifest 属性,它会请求 manifest 文件,如果是第一次访问页面 ,那么浏览器就会根据 manifest 文件的内容下载相应的资源并且进行离线存储。如果已经访问过页面并且资源已经进行离线存储了,那么浏览器就会使用离线的资源加载页面,然后浏览器会对比新的 manifest 文件与旧的 manifest 文件,如果文件没有发生改变,就不做任何操作,如果文件改变了,就会重新下载文件中的资源并进行离线存储。

  • 离线的情况下,浏览器会直接使用离线存储的资源。

当在浏览器中输入 Google.com 并且按下回车之后发生了什么?

(1)解析 URL: 首先会对 URL 进行解析,分析所需要使用的传输协议和请求的资源的路径。如果输入的 URL 中的协议或者主机名不合法,将会把地址栏中输入的内容传递给搜索引擎。如果没有问题,浏览器会检查 URL 中是否出现了非法字符,如果存在非法字符,则对非法字符进行转义后再进行下一过程。


(2)缓存判断: 浏览器会判断所请求的资源是否在缓存里,如果请求的资源在缓存里并且没有失效,那么就直接使用,否则向服务器发起新的请求。


(3)DNS 解析: 下一步首先需要获取的是输入的 URL 中的域名的 IP 地址,首先会判断本地是否有该域名的 IP 地址的缓存,如果有则使用,如果没有则向本地 DNS 服务器发起请求。本地 DNS 服务器也会先检查是否存在缓存,如果没有就会先向根域名服务器发起请求,获得负责的顶级域名服务器的地址后,再向顶级域名服务器请求,然后获得负责的权威域名服务器的地址后,再向权威域名服务器发起请求,最终获得域名的 IP 地址后,本地 DNS 服务器再将这个 IP 地址返回给请求的用户。用户向本地 DNS 服务器发起请求属于递归请求,本地 DNS 服务器向各级域名服务器发起请求属于迭代请求。


(4)获取 MAC 地址: 当浏览器得到 IP 地址后,数据传输还需要知道目的主机 MAC 地址,因为应用层下发数据给传输层,TCP 协议会指定源端口号和目的端口号,然后下发给网络层。网络层会将本机地址作为源地址,获取的 IP 地址作为目的地址。然后将下发给数据链路层,数据链路层的发送需要加入通信双方的 MAC 地址,本机的 MAC 地址作为源 MAC 地址,目的 MAC 地址需要分情况处理。通过将 IP 地址与本机的子网掩码相与,可以判断是否与请求主机在同一个子网里,如果在同一个子网里,可以使用 APR 协议获取到目的主机的 MAC 地址,如果不在一个子网里,那么请求应该转发给网关,由它代为转发,此时同样可以通过 ARP 协议来获取网关的 MAC 地址,此时目的主机的 MAC 地址应该为网关的地址。


(5)TCP 三次握手: 下面是 TCP 建立连接的三次握手的过程,首先客户端向服务器发送一个 SYN 连接请求报文段和一个随机序号,服务端接收到请求后向服务器端发送一个 SYN ACK 报文段,确认连接请求,并且也向客户端发送一个随机序号。客户端接收服务器的确认应答后,进入连接建立的状态,同时向服务器也发送一个 ACK 确认报文段,服务器端接收到确认后,也进入连接建立状态,此时双方的连接就建立起来了。


(6)HTTPS 握手: 如果使用的是 HTTPS 协议,在通信前还存在 TLS 的一个四次握手的过程。首先由客户端向服务器端发送使用的协议的版本号、一个随机数和可以使用的加密方法。服务器端收到后,确认加密的方法,也向客户端发送一个随机数和自己的数字证书。客户端收到后,首先检查数字证书是否有效,如果有效,则再生成一个随机数,并使用证书中的公钥对随机数加密,然后发送给服务器端,并且还会提供一个前面所有内容的 hash 值供服务器端检验。服务器端接收后,使用自己的私钥对数据解密,同时向客户端发送一个前面所有内容的 hash 值供客户端检验。这个时候双方都有了三个随机数,按照之前所约定的加密方法,使用这三个随机数生成一把秘钥,以后双方通信前,就使用这个秘钥对数据进行加密后再传输。


(7)返回数据: 当页面请求发送到服务器端后,服务器端会返回一个 html 文件作为响应,浏览器接收到响应后,开始对 html 文件进行解析,开始页面的渲染过程。


(8)页面渲染: 浏览器首先会根据 html 文件构建 DOM 树,根据解析到的 css 文件构建 CSSOM 树,如果遇到 script 标签,则判端是否含有 defer 或者 async 属性,要不然 script 的加载和执行会造成页面的渲染的阻塞。当 DOM 树和 CSSOM 树建立好后,根据它们来构建渲染树。渲染树构建好后,会根据渲染树来进行布局。布局完成后,最后使用浏览器的 UI 接口对页面进行绘制。这个时候整个页面就显示出来了。


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

async/await 如何捕获异常

async function fn(){    try{        let a = await Promise.reject('error')    }catch(error){        console.log(error)    }}
复制代码


参考 前端进阶面试题详细解答

TCP 和 UDP 的概念及特点

TCP 和 UDP 都是传输层协议,他们都属于 TCP/IP 协议族:


(1)UDP


UDP 的全称是用户数据报协议,在网络中它与 TCP 协议一样用于处理数据包,是一种无连接的协议。在 OSI 模型中,在传输层,处于 IP 协议的上一层。UDP 有不提供数据包分组、组装和不能对数据包进行排序的缺点,也就是说,当报文发送之后,是无法得知其是否安全完整到达的。


它的特点如下:


1)面向无连接


首先 UDP 是不需要和 TCP 一样在发送数据前进行三次握手建立连接的,想发数据就可以开始发送了。并且也只是数据报文的搬运工,不会对数据报文进行任何拆分和拼接操作。


具体来说就是:


  • 在发送端,应用层将数据传递给传输层的 UDP 协议,UDP 只会给数据增加一个 UDP 头标识下是 UDP 协议,然后就传递给网络层了

  • 在接收端,网络层将数据传递给传输层,UDP 只去除 IP 报文头就传递给应用层,不会任何拼接操作


2)有单播,多播,广播的功能


UDP 不止支持一对一的传输方式,同样支持一对多,多对多,多对一的方式,也就是说 UDP 提供了单播,多播,广播的功能。


3)面向报文


发送方的 UDP 对应用程序交下来的报文,在添加首部后就向下交付 IP 层。UDP 对应用层交下来的报文,既不合并,也不拆分,而是保留这些报文的边界。因此,应用程序必须选择合适大小的报文


4)不可靠性


首先不可靠性体现在无连接上,通信都不需要建立连接,想发就发,这样的情况肯定不可靠。


并且收到什么数据就传递什么数据,并且也不会备份数据,发送数据也不会关心对方是否已经正确接收到数据了。


再者网络环境时好时坏,但是 UDP 因为没有拥塞控制,一直会以恒定的速度发送数据。即使网络条件不好,也不会对发送速率进行调整。这样实现的弊端就是在网络条件不好的情况下可能会导致丢包,但是优点也很明显,在某些实时性要求高的场景(比如电话会议)就需要使用 UDP 而不是 TCP。


5)头部开销小,传输数据报文时是很高效的。


UDP 头部包含了以下几个数据:


  • 两个十六位的端口号,分别为源端口(可选字段)和目标端口

  • 整个数据报文的长度

  • 整个数据报文的检验和(IPv4 可选字段),该字段用于发现头部信息和数据中的错误


因此 UDP 的头部开销小,只有 8 字节,相比 TCP 的至少 20 字节要少得多,在传输数据报文时是很高效的。


(2)TCP TCP 的全称是传输控制协议是一种面向连接的、可靠的、基于字节流的传输层通信协议。TCP 是面向连接的、可靠的流协议(流就是指不间断的数据结构)。


它有以下几个特点:


1)面向连接


面向连接,是指发送数据之前必须在两端建立连接。建立连接的方法是“三次握手”,这样能建立可靠的连接。建立连接,是为数据的可靠传输打下了基础。


2)仅支持单播传输


每条 TCP 传输连接只能有两个端点,只能进行点对点的数据传输,不支持多播和广播传输方式。


3)面向字节流


TCP 不像 UDP 一样那样一个个报文独立地传输,而是在不保留报文边界的情况下以字节流方式进行传输。


4)可靠传输


对于可靠传输,判断丢包、误码靠的是 TCP 的段编号以及确认号。TCP 为了保证报文传输的可靠,就给每个包一个序号,同时序号也保证了传送到接收端实体的包的按序接收。然后接收端实体对已成功收到的字节发回一个相应的确认(ACK);如果发送端实体在合理的往返时延(RTT)内未收到确认,那么对应的数据(假设丢失了)将会被重传。


5)提供拥塞控制


当网络出现拥塞的时候,TCP 能够减小向网络注入数据的速率和数量,缓解拥塞。


6)提供全双工通信


TCP 允许通信双方的应用程序在任何时候都能发送数据,因为 TCP 连接的两端都设有缓存,用来临时存放双向通信的数据。当然,TCP 可以立即发送一个数据段,也可以缓存一段时间以便一次发送更多的数据段(最大的数据段大小取决于 MSS)

渐进增强和优雅降级之间的区别

(1)渐进增强(progressive enhancement):主要是针对低版本的浏览器进行页面重构,保证基本的功能情况下,再针对高级浏览器进行效果、交互等方面的改进和追加功能,以达到更好的用户体验。 (2)优雅降级 graceful degradation: 一开始就构建完整的功能,然后再针对低版本的浏览器进行兼容。


两者区别:


  • 优雅降级是从复杂的现状开始的,并试图减少用户体验的供给;而渐进增强是从一个非常基础的,能够起作用的版本开始的,并在此基础上不断扩充,以适应未来环境的需要;

  • 降级(功能衰竭)意味着往回看,而渐进增强则意味着往前看,同时保证其根基处于安全地带。


“优雅降级”观点认为应该针对那些最高级、最完善的浏览器来设计网站。而将那些被认为“过时”或有功能缺失的浏览器下的测试工作安排在开发周期的最后阶段,并把测试对象限定为主流浏览器(如 IE、Mozilla 等)的前一个版本。 在这种设计范例下,旧版的浏览器被认为仅能提供“简陋却无妨 (poor, but passable)” 的浏览体验。可以做一些小的调整来适应某个特定的浏览器。但由于它们并非我们所关注的焦点,因此除了修复较大的错误之外,其它的差异将被直接忽略。


“渐进增强”观点则认为应关注于内容本身。内容是建立网站的诱因,有的网站展示它,有的则收集它,有的寻求,有的操作,还有的网站甚至会包含以上的种种,但相同点是它们全都涉及到内容。这使得“渐进增强”成为一种更为合理的设计范例。这也是它立即被 Yahoo 所采纳并用以构建其“分级式浏览器支持 (Graded Browser Support)”策略的原因所在。

for...in 和 for...of 的区别

for…of 是 ES6 新增的遍历方式,允许遍历一个含有 iterator 接口的数据结构(数组、对象等)并且返回各项的值,和 ES3 中的 for…in 的区别如下


  • for…of 遍历获取的是对象的键值,for…in 获取的是对象的键名;

  • for… in 会遍历对象的整个原型链,性能非常差不推荐使用,而 for … of 只遍历当前对象不会遍历原型链;

  • 对于数组的遍历,for…in 会返回数组中所有可枚举的属性(包括原型链上可枚举的属性),for…of 只返回数组的下标对应的属性值;


总结: for...in 循环主要是为了遍历对象而生,不适用于遍历数组;for...of 循环可以用来遍历数组、类数组对象,字符串、Set、Map 以及 Generator 对象。

三栏布局的实现

三栏布局一般指的是页面中一共有三栏,左右两栏宽度固定,中间自适应的布局,三栏布局的具体实现:


  • 利用绝对定位,左右两栏设置为绝对定位,中间设置对应方向大小的 margin 的值。


.outer {  position: relative;  height: 100px;}
.left { position: absolute; width: 100px; height: 100px; background: tomato;}
.right { position: absolute; top: 0; right: 0; width: 200px; height: 100px; background: gold;}
.center { margin-left: 100px; margin-right: 200px; height: 100px; background: lightgreen;}
复制代码


  • 利用 flex 布局,左右两栏设置固定大小,中间一栏设置为 flex:1。


.outer {  display: flex;  height: 100px;}
.left { width: 100px; background: tomato;}
.right { width: 100px; background: gold;}
.center { flex: 1; background: lightgreen;}
复制代码


  • 利用浮动,左右两栏设置固定大小,并设置对应方向的浮动。中间一栏设置左右两个方向的 margin 值,注意这种方式,中间一栏必须放到最后:


.outer {  height: 100px;}
.left { float: left; width: 100px; height: 100px; background: tomato;}
.right { float: right; width: 200px; height: 100px; background: gold;}
.center { height: 100px; margin-left: 100px; margin-right: 200px; background: lightgreen;}
复制代码


  • 圣杯布局,利用浮动和负边距来实现。父级元素设置左右的 padding,三列均设置向左浮动,中间一列放在最前面,宽度设置为父级元素的宽度,因此后面两列都被挤到了下一行,通过设置 margin 负值将其移动到上一行,再利用相对定位,定位到两边。


.outer {  height: 100px;  padding-left: 100px;  padding-right: 200px;}
.left { position: relative; left: -100px;
float: left; margin-left: -100%;
width: 100px; height: 100px; background: tomato;}
.right { position: relative; left: 200px;
float: right; margin-left: -200px;
width: 200px; height: 100px; background: gold;}
.center { float: left;
width: 100%; height: 100px; background: lightgreen;}
复制代码


  • 双飞翼布局,双飞翼布局相对于圣杯布局来说,左右位置的保留是通过中间列的 margin 值来实现的,而不是通过父元素的 padding 来实现的。本质上来说,也是通过浮动和外边距负值来实现的。


.outer {  height: 100px;}
.left { float: left; margin-left: -100%;
width: 100px; height: 100px; background: tomato;}
.right { float: left; margin-left: -200px;
width: 200px; height: 100px; background: gold;}
.wrapper { float: left;
width: 100%; height: 100px; background: lightgreen;}
.center { margin-left: 100px; margin-right: 200px; height: 100px;}
复制代码

HTTP 响应报文的是什么样的?

请求报⽂有 4 部分组成:


  • 响应⾏

  • 响应头

  • 空⾏

  • 响应体

  • 响应⾏:由网络协议版本,状态码和状态码的原因短语组成,例如 HTTP/1.1 200 OK 。

  • 响应头:响应部⾸组成

  • 响应体:服务器响应的数据

GET 方法 URL 长度限制的原因

实际上 HTTP 协议规范并没有对 get 方法请求的 url 长度进行限制,这个限制是特定的浏览器及服务器对它的限制。IE 对 URL 长度的限制是 2083 字节(2K+35)。由于 IE 浏览器对 URL 长度的允许值是最小的,所以开发过程中,只要 URL 不超过 2083 字节,那么在所有浏览器中工作都不会有问题。


GET的长度值 = URL(2083)- (你的Domain+Path)-2(2是get请求中?=两个字符的长度)
复制代码


下面看一下主流浏览器对 get 方法中 url 的长度限制范围:


  • Microsoft Internet Explorer (Browser):IE 浏览器对 URL 的最大限制为 2083 个字符,如果超过这个数字,提交按钮没有任何反应。

  • Firefox (Browser):对于 Firefox 浏览器 URL 的长度限制为 65,536 个字符。

  • Safari (Browser):URL 最大长度限制为 80,000 个字符。

  • Opera (Browser):URL 最大长度限制为 190,000 个字符。

  • Google (chrome):URL 最大长度限制为 8182 个字符。


主流的服务器对 get 方法中 url 的长度限制范围:


  • Apache (Server):能接受最大 url 长度为 8192 个字符。

  • Microsoft Internet Information Server(IIS):能接受最大 url 的长度为 16384 个字符。


根据上面的数据,可以知道,get 方法中的 URL 长度最长不超过 2083 个字符,这样所有的浏览器和服务器都可能正常工作。

对盒模型的理解

CSS3 中的盒模型有以下两种:标准盒子模型、IE 盒子模型 盒模型都是由四个部分组成的,分别是 margin、border、padding 和 content。


标准盒模型和 IE 盒模型的区别在于设置 width 和 height 时,所对应的范围不同:


  • 标准盒模型的 width 和 height 属性的范围只包含了 content,

  • IE 盒模型的 width 和 height 属性的范围包含了 border、padding 和 content。


可以通过修改元素的 box-sizing 属性来改变元素的盒模型:


  • box-sizeing: content-box表示标准盒模型(默认值)

  • box-sizeing: border-box表示 IE 盒模型(怪异盒模型)

title 与 h1 的区别、b 与 strong 的区别、i 与 em 的区别?

  • strong 标签有语义,是起到加重语气的效果,而 b 标签是没有的,b 标签只是一个简单加粗标签。b 标签之间的字符都设为粗体,strong 标签加强字符的语气都是通过粗体来实现的,而搜索引擎更侧重 strong 标签。

  • title 属性没有明确意义只表示是个标题,H1 则表示层次明确的标题,对页面信息的抓取有很大的影响

  • i 内容展示为斜体,em 表示强调的文本

CSS 预处理器/后处理器是什么?为什么要使用它们?

预处理器, 如:lesssassstylus,用来预编译sass或者less,增加了css代码的复用性。层级,mixin, 变量,循环, 函数等对编写以及开发 UI 组件都极为方便。


后处理器, 如: postCss,通常是在完成的样式表中根据css规范处理css,让其更加有效。目前最常做的是给css属性添加浏览器私有前缀,实现跨浏览器兼容性的问题。


css预处理器为css增加一些编程特性,无需考虑浏览器的兼容问题,可以在CSS中使用变量,简单的逻辑程序,函数等在编程语言中的一些基本的性能,可以让css更加的简洁,增加适应性以及可读性,可维护性等。


其它css预处理器语言:Sass(Scss), Less, Stylus, Turbine, Swithch css, CSS Cacheer, DT Css


使用原因:


  • 结构清晰, 便于扩展

  • 可以很方便的屏蔽浏览器私有语法的差异

  • 可以轻松实现多重继承

  • 完美的兼容了CSS代码,可以应用到老项目中

浏览器乱码的原因是什么?如何解决?

产生乱码的原因:


  • 网页源代码是gbk的编码,而内容中的中文字是utf-8编码的,这样浏览器打开即会出现html乱码,反之也会出现乱码;

  • html网页编码是gbk,而程序从数据库中调出呈现是utf-8编码的内容也会造成编码乱码;

  • 浏览器不能自动检测网页编码,造成网页乱码。


解决办法:


  • 使用软件编辑 HTML 网页内容;

  • 如果网页设置编码是gbk,而数据库储存数据编码格式是UTF-8,此时需要程序查询数据库数据显示数据前进程序转码;

  • 如果浏览器浏览时候出现网页乱码,在浏览器中找到转换编码的菜单进行转换。

map 和 Object 的区别

如何使用 for...of 遍历对象

for…of 是作为 ES6 新增的遍历方式,允许遍历一个含有 iterator 接口的数据结构(数组、对象等)并且返回各项的值,普通的对象用 for..of 遍历是会报错的。


如果需要遍历的对象是类数组对象,用 Array.from 转成数组即可。


var obj = {    0:'one',    1:'two',    length: 2};obj = Array.from(obj);for(var k of obj){    console.log(k)}
复制代码


如果不是类数组对象,就给对象添加一个[Symbol.iterator]属性,并指向一个迭代器即可。


//方法一:var obj = {    a:1,    b:2,    c:3};
obj[Symbol.iterator] = function(){ var keys = Object.keys(this); var count = 0; return { next(){ if(count<keys.length){ return {value: obj[keys[count++]],done:false}; }else{ return {value:undefined,done:true}; } } }};
for(var k of obj){ console.log(k);}

// 方法二var obj = { a:1, b:2, c:3};obj[Symbol.iterator] = function*(){ var keys = Object.keys(obj); for(var k of keys){ yield [k,obj[k]] }};
for(var [k,v] of obj){ console.log(k,v);}

复制代码

forEach 和 map 方法有什么区别

这方法都是用来遍历数组的,两者区别如下:


  • forEach()方法会针对每一个元素执行提供的函数,对数据的操作会改变原数组,该方法没有返回值;

  • map()方法不会改变原数组的值,返回一个新数组,新数组中的值为原数组调用函数处理之后的值;

link 和 @import 的区别

两者都是外部引用 CSS 的方式,它们的区别如下:


  • link 是 XHTML 标签,除了加载 CSS 外,还可以定义 RSS 等其他事务;@import 属于 CSS 范畴,只能加载 CSS。

  • link 引用 CSS 时,在页面载入时同时加载;@import 需要页面网页完全载入以后加载。

  • link 是 XHTML 标签,无兼容问题;@import 是在 CSS2.1 提出的,低版本的浏览器不支持。

  • link 支持使用 Javascript 控制 DOM 去改变样式;而 @import 不支持。


用户头像

loveX001

关注

还未添加个人签名 2022-09-01 加入

还未添加个人简介

评论

发布
暂无评论
前端必会面试题_JavaScript_loveX001_InfoQ写作社区