前端常见面试题

浏览器

输入一个URL到页面过程中发生了什么

  1. 首先在浏览器中输入URL地址

  2. 查找缓存:浏览器先查看浏览器缓存-系统缓存-路由缓存中是否有该地址页面,如果有则显示页面内容。如果没有则进行下一步。

  3. 首先判断输入的东西是否为域名并且合法,如果不合法,直接使用浏览器的搜索引擎进行搜索,如果合法,如果是域名的话进行DNS域名解析将其进行IP地址转化并访问该IP地址,如果是IP,直接打开。(DNS域名解析:浏览器向DNS服务器发起请求,解析该URL中的域名对应的IP地址。DNS服务器是基于UDP的,因此会用到UDP协议。)

  4. 输入 IP访问是不会输入端口号的,那么如果是http协议的话,默认端口是80端口,如果是https协议的话,默认端口是443。如果是https协议,会进行加密操作(SSL加密协议),此时已经拿到了完整的路径。

  5. 如果是nginx的话,会进行路径匹配。

  6. 建立TCP连接:解析出IP地址后,根据IP地址和默认80端口,和服务器建立TCP连接

  7. 发起HTTP请求:浏览器发起读取文件的HTTP请求,该请求报文作为TCP三次握手的第三次数据发送给服务器

  8. 服务器响应请求并返回结果:服务器对浏览器请求做出响应,并把对应的html文件发送给浏览器

  9. 关闭TCP连接:通过四次挥手释放TCP连接

  10. 浏览器渲染:客户端(浏览器)解析HTML内容并渲染出来,浏览器接收到数据包后的解析流程为:

构建DOM树:词法分析然后解析成DOM树(dom tree),是由dom元素及属性节点组成,树的根是document对象

构建CSS规则树:生成CSS规则树(CSS Rule Tree)

构建render树:Web浏览器将DOM和CSSOM结合,并构建出渲染树(render tree)

布局(Layout):计算出每个节点在屏幕中的位置

绘制(Painting):即遍历render树,并使用UI后端层绘制每个节点。

TCP 三次握手和四次挥手

三次握手和四次挥手

  1. 三次握手:

第一次握手:客户端向服务端发送包含自身初始序号 x 的同步报文,进入 SYN-SENT 状态。

第二次握手:服务端收到连接请求报文段后,会将连接放入半连接队列中,并向客户端发送包含自身初始序号 y 的同步确认报文,进入 SYN-RECEIVED 状态。

第三次握手:客户端收到应答,向服务端发送确认报文,进入 ESTABLISHED 状态,此时成功建立长连接。

  1. 四次挥手:

第一次挥手:客户端数据发送完毕,向服务端发送终止报文请求释放连接。

第二次挥手:服务器收到连接释放请求,告诉应用层释放 TCP 连接。然后发送确认报文,进入 CLOSE-WAIT 状态,此时表明客户端到服务端的连接已经释放,不再接受客户端的数据。但因为 TCP 是全双工的,所以服务器仍可以发送数据。

第三次挥手:当服务端数据发送完毕,向客户端发送终止报文,发送连接释放请求,进入 LAST-ACK 状态。

第四次挥手:客户端收到连接释放请求,向服务器端发送 确认报文,此时客户端进入 TIME-WAIT 状态,会等待 2MSL(最长报文段寿命),若期间没有收到服务器端的数据报文,进入 CLOSED 状态。服务器端在收到确认应答后也进入 CLOSED 态。

为什么是三次握手而不是两次或者四次

两次不安全,四次没必要。

TCP 通信需要确保双方都具有数据收发的能力。

第一次带有 SYN 的 ACK 向客户端表明了服务端的收发能力,同时也验证了客户端自己的收发能力。

第二次的 ACK 则向服务端表明了客户端的收发能力(更准确来说是接收能力,因为第一条 SYN 就已经证明了客户端的发送能力),同时也验证了服务端自己的收发能力。

三次握手哪次可以携带数据

第一次和第二次不能携带数据,第三次可以携带数据。

如果第一条同步报文可以携带数据,当有人恶意攻击服务器时,就可以在第一次握手中携带大量额外数据来攻击服务器缓存。

第二次握手由服务器发起,服务器作为被动连接方,没有必要携带数据。

三次握手失败服务器会如何处理

握手失败有两种情况:

一种情况是服务端没有收到 SYN,此时不会做任何响应。

另一种情况是服务端在回复了 SYN + ACK 报文后长时间没有收到 ACK 响应,此时服务端会按照一定时间间隔重传一定次数的 SYN + ACK 报文,如果重传指定次数后仍未收到客户端的 ACK 响应,服务端会发送 RST 报文重置连接,释放资源。

为什么握手三次,而挥手需要四次

TCP 握手时服务端将 SYN 和 ACK 合并在一个包中发送,因此减少了一次握手。

对于四次挥手,由于 TCP 是全双工通信,客户端(或者说主动关闭方)发送 FIN 请求只能表示客户端不再发送数据了,不代表完全断开连接,服务端(或者说被动关闭方)可能还要发送数据。所以不能将服务端的 FIN 包和对客户端的 ACK 包合并发送,只能先确认主动关闭方的 FIN,等服务端数据发送完毕时再发送 FIN 包,故挥手需要四次。

tcp和udp

概念:

传输控制协议(TCP):TCP(传输控制协议)定义了两台计算机之间进行可靠的传输而交换的数据和确认信息的格式,以及计算机为了确保数据的正确到达而采取的措施。TCP最大的特点就是提供的是面向连接、可靠的字节流服务。

用户数据报协议(UDP):UDP(用户数据报协议)是一个简单的面向数据报的传输层协议。提供的是非面向连接的、不可靠的数据流传输。

TCP:

在使用TCP协议进行数据传输时,往往需要客户端和服务端先建立一个“通道“、且这个通道只能够被客户端和服务端使用,所以TCP传输协议只能面向一对一的连接。

通道的建立——三次握手:

(1)在建立通道时,客户端首先要向服务端发送一个SYN同步信号。

(2)服务端在接收到这个信号之后会向客户端发出SYN同步信号和ACK确认信号。

(3)当服务端的ACK和SYN到达客户端后,客户端与服务端之间的这个“通道”就会被建立起来。

通道的关闭——四次挥手:

(1)在数据传输完毕之后,客户端会向服务端发出一个FIN终止信号。

(2)服务端在收到这个信号之后会向客户端发出一个ACK确认信号。

(3)如果服务端此后也没有数据发给客户端时服务端会向客户端发送一个FIN终止信号。

(4)客户端在收到这个信号之后会回复一个确认信号,在服务端接收到这个信号之后,服务端与客户端的通道也就关闭了。

应用场景:TCP主要应用于文件传输精确性相对要求较高且不是很紧急的情景,比如电子邮件、远程登录等。

UDP:

UDP传输协议是一种不可靠的、面向无连接、可以实现多对一、一对多和一对一连接的通信协议。UDP在传输数据前既不需要建立通道,在数据传输完毕后也不需要将通道关闭。只要客户端给服务端发送一个请求,服务端就会一次性地把所有数据发送完毕。UDP在传输数据时不会对数据的完整性进行验证,在数据丢失或数据出错时也不会要求重新传输,因此也节省了很多用于验证数据包的时间,所以以UDP建立的连接的延迟会比以TCP建立的连接的延迟更低。UDP不会根据当前的网络情况来控制数据的发送速度,因此无论网络情况是好是坏,服务端都会以恒定的速率发送数据。

应用场景:UDP被广泛应用于数据量大且精确性要求不高的数据传输,比如我们平常在网站上观看视频或者听音乐。

TCP和UDP的区别

  1. 是否连接:tcp是面向连接,udp无连接;
  2. 传输可靠性:tcp是可靠的,udp不可靠;
  3. 应用场景:tcp传输大量数据,udp传输少量数据;
  4. 速度:tcp传输速度慢,udp传输速度快。

超文本传输协议的超文本怎么理解

超文本传输协议一般指http协议。超文本-不是单纯的文本,包括一些文件图片这样的二进制流

浏览器渲染机制、重绘、重排

浏览器渲染机制即网页生成的过程

构建DOM树:词法分析然后解析成DOM树(dom tree),是由dom元素及属性节点组成,树的根是document对象

构建CSS规则树:生成CSS规则树(CSS Rule Tree)

构建render树:Web浏览器将DOM和CSSOM结合,并构建出渲染树(render tree)

布局(Layout):计算出每个节点在屏幕中的位置

绘制(Painting):即遍历render树,并使用UI后端层绘制每个节点。

重排

重排:当DOM的变化影响了元素的几何信息(DOM对象的位置和尺寸大小),浏览器需要重新计算元素的几何属性,将其安放在界面中的正确位置,这个过程叫做重排。

触发条件:

  1. 添加或者删除可见的DOM元素

  2. 元素尺寸改变——边距、填充、边框、宽度和高度

重绘

重绘:当一个元素的外观发生改变,但没有改变布局,重新把元素外观绘制出来的过程,叫做重绘。

触发条件:改变元素的color、background、box-shadow等属性

网络安全

GET和POST

GET和POST的区别

get和post本质没有什么区别,都是TCP/IP协议请求的一种形式,只不过因为浏览器以及各大厂商的规定,限制了每一种请求有自己特定的用途。常说的get和post请求的区别实际上是参数放到请求头和请求体里面用法的区别

GET和POST参数应用场景的区别

  1. GET在浏览器回退不会再次请求,POST会再次提交请求

  2. GET请求会被浏览器主动缓存,POST不会,要手动设置

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

  4. GET请求在URL中传送的参数是有长度限制的,而POST没有限制

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

  6. GET参数暴露在地址栏不安全,POST放在报文内部更安全

  7. GET一般用于查询信息,POST一般用于提交某种信息进行某些修改操作

  8. GET产生一个TCP数据包;POST产生两个TCP数据包

HTTP和HTTPS

http 和 https 的基本概念

http: 是一个客户端和服务器端请求和应答的标准(TCP),用于从 WWW 服务器传输超文本到本地浏览器的超文本传输协议。

https:是以安全为目标的 HTTP 通道,即 HTTP 下 加入 SSL 层进行加密。其作用是:建立一个信息安全通道,来确保数据的传输,确保网站的真实性。

http 和 https 的区别

  1. HTTP 的URL 以http:// 开头,而HTTPS 的URL 以https:// 开头

  2. HTTP 是不安全的,而 HTTPS 是安全的

  3. HTTP 标准端口是80 ,而 HTTPS 的标准端口是443

  4. 在OSI 网络模型中,HTTP工作于应用层,而HTTPS 的安全传输机制工作在传输层

  5. HTTP 无法加密,而HTTPS 对传输的数据进行SSL加密

  6. HTTP无需证书,而HTTPS 需要CA机构wosign的颁发的SSL证书(SSL加密协议)

http状态码

  1. 200响应成功
  2. 301永久重定向
  3. 302临时重定向
  4. 304资源缓存
  5. 401未登录
  6. 403服务器禁止访问
  7. 404服务器资源未找到
  8. 500 502服务器内部错误 504 服务器繁忙

性能相关

浏览器的存储方式

浏览器的存储方式主要分为cookie、localStorage和sessionStorage。

浏览器三种存储方式的相同点:

共同点: 都是保存在浏览器端、仅同源可用的本地存储方式

浏览器三种存储方式的不同点(web storage和cookie的区别):

  1. 从存储数据的大小来说:cookie数据不能超过4K,sessionStorage和localStorage可以达到5M。
  2. 从存储数据的种类来说:web storage存储的数据可以是JSON对象,也可以是字符串,而cookie只能是字符串。
  3. 从存储数据的有效期来说:sessionStorage关闭浏览器窗口就删除了,localStorage是永久存储,只有主动删除才会删除掉,cookie必须设置有效期,有效期到了就删除,也可以主动删除。
  4. 从存储数据的作用域来说:sessionStorage作用于本窗口,localstorage和cookie作用于所有的同源页面(同源:协议名,域名,端口名都相同

浏览器的同源策略

浏览器的同源策略:协议相同,域名相同,端口相同(如果他们三个有一个不一致,就会出现跨域现象)

解决请求跨域的方法

  1. jsonp(利用script标签没有跨域限制的漏洞实现。缺点:只支持GET请求)
  2. CORS(设置Access-Control-Allow-Origin:指定可访问资源的域名)
  3. proxy代理 目前常用方式,通过服务器设置代理
  4. 利用h5新特性window.postMessage()

加密方式

  1. md5加密(不可逆)322位
  2. RSA 非对称加密,分为公钥(在服务器上)和私钥。(不规则图形可以对一起)
  3. SHa加密

防抖

多次触发事件,事件处理函数只能执行一次,并且是在触发操作结束时执行。也就是说,当一个事件被触发准备执行事件函数前,会等待一定的时间(这时间是自己去定义的,比如 1 秒),如果没有再次被触发,那么就执行,如果被触发了,那就本次作废,重新从新触发的时间开始计算,并再次等待 1 秒,直到能最终执行。(如输入框中输入内容,只执行最后一次)

一定时间内方法只执行最后一次。

// 由于作用域的原因,声明定时器let timer必须放在页面构造器Page外边,否则无法清除定时器队列,导致重复触发!
let timer;
Page({
  debounce(e){
    // 清除之前的定时器
    clearTimeout(timer);
    // 只有一个定时器,把事件放到定时器中,每次都执行最后一次的事件,其他事件会被清空
    timer = setTimeout(() => {
      console.log(e.detail.scrollTop)
    }, 500);
  }
})

节流

事件触发后,规定时间内,事件处理函数不能再次被调用。也就是说在规定的时间内,函数只能被调用一次,且是最先被触发调用的那次。(如浏览器窗口不停 的拖动,只执行第一次)

一定时间内多次执行,只执行第一次。

Page({
  data: {
    // 定义一个事件锁
    lock: true
  },
  throttling(e){
    let timer
    // 只有当锁为true的时候才会执行里面的代码,把事件放到里面
    if(this.data.lock){
      // 每次都先把锁变为false
      this.lock = false;
      setTimeout(()=>{
        // 在定时器内把锁变为true,然后执行事件,这个事件在定时器执行时间内不会被触发
        this.lock = true;
        console.log(e.detail.scrollTop)
      },500)
    }
  }
})

HTML

语义化标签

用正确的标签做正确的事

常见的语义化标签

<header>: 头部标签
<nav>: 导航标签
<article>: 内容标签
<section>: 定义文档某个区域
<aside>: 侧边栏标签
<footer>: 底部标签

语义化的优点

  1. 使页面结构更加的清晰
  2. 有利于SEO和搜索引擎建立良好的沟通,有助于爬虫抓取更多的有效信息,爬虫是依赖于标签来确定上下文和各个关键字的权重。
  3. 方便团队开发和维护,语义化更具可读性,遵循W3C标准的团队都遵循这个标准,可以减少差异化

HTML5的新特性

  1. 语义化标签 <header><footer>
  2. 音频,视频<audio src=""></audio>,<video src=""></video>
  3. 本地存储 localstorage和sessionstorage
  4. canvas画布
  5. 超链接协议,解决跨域的新方法,websocket
  6. 增强型表单,如email,time,seach

script标签中defer和async的区别

多个带async属性的标签,不能保证加载的顺序;多个带defer属性的标签,按照加载顺序执行;
async属性,表示后续文档的加载和执行与js脚本的加载和执行是并行进行的,即异步执行;defer属性,加载后续文档的过程和js脚本的加载(此时仅加载不执行)是并行进行的(异步),js脚本需要等到文档所有元素解析完成之后才执行,DOMContentLoaded事件触发执行之前。

CSS

CSS3中有哪些新特性

新增各种CSS选择器 (: not(.input):所有 class 不是“input”的节点)

  1. 边框:阴影box-shadow,圆角 border-radius
  2. 背景:backgroud-img, backgroud-color
  3. 2D转换,3D转换 transform
  4. 过渡
  5. 动画
  6. 媒体查询
  7. 多栏布局
  8. css选择器,盒模型
  9. 线性渐变

盒模型

盒模型都是由四个部分组成的,分别是margin、border、padding和content。

标准盒模型和IE盒模型

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

IE盒模型转化为标准盒模型: box-sizing:content-box
标准盒模型转化为IE盒模型:box-sizing:border-box

盒子水平垂直居中方法

1.

在这里插入图片描述

2.

在这里插入图片描述

3.

在这里插入图片描述

4.

在这里插入图片描述

5.

在这里插入图片描述

隐藏元素的方法有哪些

  1. 使用display: none; 隐藏dom;
  2. 使用visibility: hidden; 隐藏dom;
  3. 使用z-index: -888; 把元素的层级调为负数,然后其他元素覆盖即可;
  4. 使用opacity: 0; 把元素的透明度调为0,也可以达到隐藏;
  5. 使用固定定位position: absolute; 把元素定位到看不见的区域;
  6. 使用transform: scale(0, 0); 把元素缩放为0,也可以实现元素隐藏。

flex常用属性

display:flex;
flex-direction: column;或者flex-direction: row;
align-items: center;
justify-content: center;
flex-wrap: nowrap;
  1. flex-direction属性决定主轴的方向(即项目的排列方向)。
  2. align-items属性定义项目在交叉轴上如何对齐。
  3. justify-content属性定义了项目在主轴上的对齐方式。
  4. flex-wrap属性定义,如果一条轴线排不下,如何换行。
  5. flex-flow属性是flex-direction属性和flex-wrap属性的简写形式,默认值为row nowrap
/* 拉伸,但是子盒子不要给高度,可以继承父盒子的高度 */
align-items: stretch;

## position属性

position: fixed;
position: relative;
position: absolute;
top: 0;
left: 0;
  1. 固定定位 fixed: 元素的位置相对于浏览器窗口是固定位置,即使窗口是滚动的它也不会移动。Fixed 定 位使元素的位置与文档流无关,因此不占据空间。 Fixed 定位的元素和其他元素重叠。
  2. 相对定位 relative: 如果对一个元素进行相对定位,它将出现在它所在的位置上。然后,可以通过设置垂直 或水平位置,让这个元素“相对于”它的起点进行移动。 在使用相对定位时,无论是 否进行移动,元素仍然占据原来的空间。因此,移动元素会导致它覆盖其它框。
  3. 绝对定位 absolute: 绝对定位的元素的位置相对于最近的已定位父元素,如果元素没有已定位的父元素,那 么它的位置相对于。absolute 定位使元素的位置与文档流无关,因此不占据空间。 absolute 定位的元素和其他元素重叠。
  4. 粘性定位 sticky: 元素先按照普通文档流定位,然后相对于该元素在流中的 flow root(BFC)和 containing block(最近的块级祖先元素)定位。而后,元素定位表现为在跨越特定阈值前为相对定 位,之后为固定定位。
  5. 默认定位 Static: 默认值。没有定位,元素出现在正常的流中(忽略 top, bottom, left, right 或者 z-index 声 明)。 inherit: 规定应该从父元素继承 position 属性的值。

transition和animation的区别

transition是过度属性,强调过度,它的实现需要触发一个事件(比如鼠标移动上去,焦点,点击等)才执行动画。它类似于flash的补间动画,设置一个开始关键帧,一个结束关键帧。

animation是动画属性,它的实现不需要触发事件,设定好时间之后可以自己执行,且可以循环一个动画。它也类似于flash的补间动画,但是它可以设置多个关键帧(用@keyframe定义)完成动画。

CSS样式优先级

选择器:
ID选择器(权重100,#demo)> 类选择器(10,.demo),伪类选择器(10,:link),属性选择器(10) > 伪元素选择器(1,::after),标签选择器(1) > 通配符(0,*),特殊的伪元素选择器(0,:not())

写法:

!important > 内联(行内)样式 (

) > 内部样式表() > 外部样式表(link引入)

伪类:四个伪类,link未访问,visited访问过后,hover移动,active点击下去时。顺序:link,visited,hover,active

BFC

块格式化上下文。

  1. 根元素或者其他包含它的元素
  2. 浮动元素,float不为none
  3. 绝对定位元素,position为absolute或者fixed
  4. 内联块:display:inline-block
  5. overflow:hidden,具有overflow不是visible
  6. 表格单元格,dispaly:table-cell
  7. display:flow-root

1px,1em,1rem,1vw / 1vh,rpx

  1. 1px

相对长度单位,像素 px 是相对于显示器屏幕分辨率而言的,一般电脑的分辨率有{19201024}等不同的分辨率,19201024 前者是屏幕宽度总共有1920个像素,后者则是高度为1024个像素。

  1. 1em

em 就是相对于自身字体 fontSize 的大小,如果自身指定 fontSize = 20px,父元素 fontSize = 30px,那么 1em = 20px;如果自身没有指定,则是继承来自于父元素的 fontSize,1em = 30px。

  1. 1rem
    rem 是全部的长度都相对于根元素 <html>fontSize 的大小,如果 <html>的 fontSize = 20px,那么 1rem = 20px。
    rem的计算方法:

假如设计图是按 640px 来设计的,那么我把设计图分成 10份(随你自己分),也就是 640px = 10rem,那么就是 1rem = 64px, 在根元素 <html>上设置的 font-size 实际就是给网页的一个标准,它的px是多少,那么子级的 1rem 就等于多少。那么在 640px的屏幕下,根元素 <html >的 font-size 就可以计算为 640/10,但是屏幕是不指定大小的,如果屏幕缩小的,那么根元素的值也要按百分比来缩小,如:屏幕如果缩到了一半 320,(320/640)*(640/10)(屏幕宽度/设计图) *(设计图/设计图的总分成)。

  1. 1vw / 1vh
    相当于屏幕宽度 / 高度的 1%,不过,处理宽度的时候 % 单位更合适,处理高度的话 vh 单位更好。

  2. rpx
    rpx是解决自适应屏幕尺寸的尺寸单位,宽度为固定的750rpx。比如iPhone6的屏幕宽度是375px,那就是1px=2rpx。

前端的五种布局方法

  1. 传统布局(静态布局div): 以固定的px为单位
  2. 自适应布局:使用媒体查询
  3. 流式布局:用百分比定义宽度,高度一般以px为固定单位
  4. 响应式布局:媒体查询 + 百分比
  5. 弹性布局:伸缩布局和rem单位搭配使用

JS

JS的数据类型

基本类型

Number、String、Boolean、Null、Undefined、Symbol

引用类型(复杂的数据类型)

Object、Date、Function、Array、RegExp正则

JS的类型检测

typeof

instanceof

Object.prototype.toString.call()

null和undefined的区别

  1. undefined是由null派生出来的
  2. null指对象的属性值为空。而undefined是一个变量的值为空,声明了但未赋值。
  3. null的typeof为object,undefined的typeof为undefined

null == undefined ; null !== undefined

JSON字符串和JSON对象的相互转化

JSON字符串转化为JSON对象:JSON.parse()

JSON对象转化为JSON字符串:JSON.stringify()

什么是事件流

Dom事件流包括三个阶段:1.事件捕获阶段。2.目标阶段。3.事件冒泡阶段。

事件代理(又叫事件委托)

事件代理采取的是冒泡机制。子元素需要绑定的事件委托给父元素,减少Dom操作,提高性能。

阻止冒泡,阻止默认事件

阻止冒泡:ev.stopProragation();

IE阻止冒泡:ev.cancelBubble = true;

阻止默认事件:ev.preventDefault();

IE阻止默认事件: return value;

既能阻止冒泡,又能阻止默认事件:return false;

垃圾回收机制

由一个单独的进程访问的,由系统控制的,浏览器每隔一段时间会清理一次无用的变量或者方法的浏览器机制叫做垃圾回收机制。

什么是内存泄漏

一个函数的作用域始终占用着另外一个函数的作用域中的变量,导致另一个函数的作用域始终占用着系统的内存空间,始终无法释放。假如同时开启很多脚本,当达到一定的程度的时候,会导致系统崩溃。

常见的内存泄漏:

  1. 意外的全局变量。
  2. 如果setTimeout的第一个参数使用字符串而非函数,会引发内存泄漏。
  3. 闭包、控制台日志、循环等。

内存泄漏的解决方法:立即执行函数可以解决内存泄漏。

作用域

作用域:函数和变量可以访问的区域。有全局作用域和局部作用域。

作用域链

作用域链: 当需要从局部函数查找某一个方法和属性的时候,如果当前作用域没有找到,就会向外查找上层作用域,直到全局函数,这就形成了作用域链。

原型

每个 class都有显示原型 prototype

每个实例都有隐式原型 _ proto_

实例的_ proto_指向对应 class 的 prototype

原型链

原型链: 当我们访问一个对象的属性时,如果这个对象内部不存在这个属性,那么它就会去它的原型对象里找这个属性,这个原型对象又会有自己的原型,于是就这样一直找下去,也就是原型链的概念

特点: JavaScript对象是通过引用来传递的,我们创建的每个新对象实体中并没有一份属于自己的原型副本。当我们修改原型时,与之相关的对象也会继承这一改变。

闭包

闭包是指有权在一个函数内部去访问另一个函数作用域中的变量,并在这个函数中调用。(会导致内存泄漏,本身无法解决,但可以避免)

function createCounter() {
  let count = 0;
  return function() {
    count++;
    return count;
  };
}

const counter = createCounter();
console.log(counter()); // 输出: 1
console.log(counter()); // 输出: 2
console.log(counter()); // 输出: 3

闭包形成的条件

  1. 函数的嵌套
  2. 内部函数引用外部函数的局部变量,延长外部函数的变量生命周期

闭包用途(好处)

  1. 可以让一个变量长期在内存中不被释放
  2. 避免全局变量的污染,和全局变量不同,闭包中的变量无法被外部使用
  3. 私有成员的存在,无法被外部调用,只能直接内部调用

闭包缺点

会导致函数的变量一直保存在内存中,过多的闭包可能会导致内存泄漏

面向对象

面向对象其实是一种思想,是把事物封装成对象,通过操作对象的属性和方法来解决问题。

面向对象的三大特征:封装,继承和多态。

继承:父元素中定义相同的属性和方法,所有的子类不需要重新定义这些属性和方法。

继承方式:原型链继承,构造函数继承,组合继承,原型式继承,寄生式继承,拷贝继承。

如何创建一个对象

  1. 通过对象字面量的方式
  2. 通过new的方法创建
  3. 通过Object.creat()

虚拟DOM

虚拟DOM就是用JS对象结构表示DOM结构,然后再用这个树构建真正的DOM树放到页面中去,当我们这个虚拟DOM以JS结构的形式存在,计算性能较好,并且由于减少了实际DOM操作的次数,性能会有较大的提升。

优点:因为Javascript的运算速度远大于DOM操作的执行速度,因此,运用patching算法来计算出真正需要更新的节点,最大限度地减少DOM操作,从而提高性能。减少了浏览器的回流和重绘

缺点:首次显示要慢些:首次渲染大量DOM时,由于多了一层虚拟DOM的计算, 会比innerHTML插入慢。

new运算符的实现机制

  1. 首先创建了一个新的空对象

  2. 设置原型,将对象的原型设置为函数的prototype对象。

  3. 让函数的this指向这个对象,执行构造函数的代码(为这个新对象添加属性)

  4. 判断函数的返回值类型,如果是值类型,返回创建的对象。如果是引用类型,就返回这个引用类型的对象。

强制类型转换和隐式类型转换

强制类型转换:

  1. parseInt(),把其他类型强制转换成数字类型,int类型
  2. parseFloat(),把其他类型强制转换成数字类型,float类型
  3. Number(),把其他类型强制转换成数字类型
  4. Boolean(),把其他类型强制转换成布尔类型
  5. String(),把其他类型强制转换成字符串类型

隐式类型转换:

  1. +,-,*,/ 操作符的隐式类型转换
  2. 逻辑运算符 || &&
  3. 一元运算符 + -
    空字符串转化为0,非空字符串转化为1

0转化为布尔类型false,除了0以外的数都是true

{}+[] = 0,[]+{} = [Object Object]

call,apply,bind的区别

它们都可以放变this指向。

区别: call理论上有无数个参数,第一个参数数是要改变的this指向的对象的对象名,第二参数是要改变的对象的属性名…,第n参数都是要改变的对象的属性名。

而apply只有两个参数,第一个数是要改变this指向的对象的对象名,第二参数是要改变的属性名整合成的一个数组。

bind的用法与apply一样,区别在于bind返回的是一个函数体,只有在调用的时候才会执行这个函数体。

this指向

  1. 创建一个空对象

  2. 改变this指句, 将构造函数的原型对象指向该空对象的原型

  3. 解释执行构造函数中的代码,将属性和方法添加到空对象中

  4. 看构造函数是否返回对象,如果是,那么new操作符返回的对象就是构造函数返回的对象,如果没有,那么new操作符返回的对象就是刚创建的那个对象。

AJAX实现原理

AJAX就是浏览器提供API,通过JS调用,从而实现通过代码实现请求和响应。

实现原理:

  1. 创建一个XMLHttpRequest
var xhr = new XMLHttpRequest()
  1. open三个参数,分别是get/post , url地址 ,是否异步(true/false)
xhr.open("GET","http://-----",false)
  1. 监听 onreadystatechange,判断readystate属性(五个值,0,1,2,3,4),判断当值为4的时候为成功 readystate == 4 && state == 200
xhr.onreadystatechange = function(){
	if(xhr.readystate != 4){
	    return
	}
    if(xhr.readystate == 4 && xhr.state == 200){
         console.log(xhr.responseText)
    }
}
  1. 敲回车,send发送请求
xhr.send()

Ajax的优势:

①减轻了客户端的内存消耗,Ajax的理念是"按需取数据"。

②无刷新更新页面,提高用户体验。

③将一部分的工作量嫁到客户端,减轻服务器压力

ajax嵌套问题

一个请求需要另一个请求返回的结果作为参数时,就是ajax嵌套,会引起回调地狱的问题,上一个ajax报错,下面的都无法执行。解决方法:使用promise来解决回调地狱的问题。

Axios

Axios 是一个基于 Promise 的 HTTP 库,可以用在浏览器和 node.js 中。

Axios有那些特性?

  1. 在浏览器中创建 XMLHttpRequests
  2. 在node.js则创建http请求
  3. 支持Promise API
  4. 支持拦截请求和响应
  5. 转换请求和响应数据
  6. 取消请求
  7. 自动转换成JSON数据格式
  8. 客户端支持防御XSRF

Axios和Ajax的区别

axios是通过Promise实现对ajax技术的一种封装,简单来说就是ajax技术实现了局部数据的刷新,axios实现了对ajax的封装,axios有的ajax都有,ajax有的axios不一定有。

map 跟 forEach 的区别

map有返回值 forEach 没有返回值

遍历数组的方法

forEach, map, some, every, reduce累加器

常用的操作数组的方法

pop 删除数组末尾元素

push 在数组末尾添加元素

shift 删除数组中的第一个元素

unshift 在数组头部添加元素,返回一个新数组

concat 合并数组,返回一个新数组

slice[start索引, end索引) 截取数组,左闭右开,未修改原数组

splice(index, howmany) 删除数组元素,从哪开始,删除几个

splice(index,howmany,item) 先删除后追加,后面可支持添加多个元素

sort 按照ascll码进行排序,sort方法中一个函数作为参数,函数中又有两个参数可实现升序降序

join 将数组转化为字符串

(split 可以将字符串转化为数组)

常用的操作字符串的方法

concat() 用于连接两个或者多个字符串,不改变原字符串

indexOf() 检索返回某个字符串开头首次出现的位置,没有找到返回-1

lastIndexOf() 查找字符串最后出现的位置

slice[start索引, end索引) 提取字符串中的某一部分(-1是最后一个,-2是倒数第二个)

split(“,”) 将字符串转化为数组,参数是用什么进行分割

toString() 强制转化为字符串

toLowerCase() 转化为小写

ES6

var/let/const

  1. ES6之前只有全局作用域和函数作用域,没有块级作用域的概念。var定义的变量,没有块的概念,可以跨块访问, 不能跨函数访问。 let定义的变量,只能在块作用域里访问,不能跨块访问,也不能跨函数访问。 const用来定义常量,使用时必须初始化(即必须赋值),只能在块作用域里访问,且不能修改。
  2. var可以先使用,后声明,因为存在变量提升;let必须先声明后使用。
  3. var是允许在相同作用域内重复声明同一个变量的,而let与const不允许这一现象。
  4. 会产生暂时性死区。
var tmp = 123;

if (true) {
  // 存在全局变量tmp,但是块级作用域内let又声明了一个局部变量tmp,导致后者绑定这个块级作用域,
     所以在let声明变量前,对tmp赋值会报错
  tmp = 'abc'; // ReferenceError
  let tmp;
}

解构赋值

数组的解构赋值

是有顺序的,按照索引:

let [a, b, c] = [1, 2, 3];
console.log(b, a, c); // 2, 1, 3

可以进行嵌套,都是按照顺序的。如果解构赋值不成功,会返回undefined。

let [bar3, foo3] = [1000];
console.log(bar3, foo3); // 1000 undefined

默认可以引用解构赋值的其他变量,但该变量必须已声明

let [a = 1, b = a] = [2, 3];
console.log(a, b); // 2 3
// 如果赋的值是[],那么a,b的值就是前面的默认值

对象的解构赋值

对象的属性没有顺序,是根据属性名来决定的。遍历必须与属性同名才能取到正确的值。

let {b, a} = {a: 'apple', b: 'banana'};
console.log(a, b); // apple banana

如果变量名与属性名不一致,给变量起一个别名:

let obj = {first: 'hello', last: 'world'};
// 把first变量重新命名为f
let {first: f, last} = obj; 
console.log(f, last); // hello world

深拷贝和浅拷贝

深拷贝和浅拷贝是针对复杂的数据类型,浅拷贝是拷贝的堆内存里面的地址,深拷贝是拷贝的堆内存里面的内容。

如果直接将arr1赋值给arr2,此时只是把堆内存里面的地址赋值了一下,它们指向堆内存里面同一个内容,所以只是浅拷贝。

var arr1 = [1, 2, 3];
var arr2 = arr1;
arr1.push(4);
console.log(arr1, arr2); // [1, 2, 3, 4], [1, 2, 3, 4]

传统的深拷贝就是定义一个空数组,但是数组里面多层嵌套,一步一步遍历直到基本数据类型:

var arr1 = [1, 2, 3];
var arr2 = [];
for(var i = 0; i < arr1.length; i++){
  arr2[i] = arr1[i]
}
arr2.push(4);
console.log(arr1, arr2); // [1, 2, 3], [1, 2, 3, 4]

ES6深拷贝:

使用Array.from()

var arr1 = [1, 2, 3];
var arr2 = Array.from(arr1);
arr2.push(100);
console.log(arr1, arr2); // [1, 2, 3], [1, 2, 3, 100]

使用扩展运算符

var arr1 = [1, 2, 3];
var arr2 = [...arr1];
arr2.push(100);
console.log(arr1, arr2); // [1, 2, 3], [1, 2, 3, 100]

对象深拷贝,只能用扩展运算符

function show(...args){
  args.push(5);
  console.log(args);  // [1, 2, 3, 4, 5]
}
show(1, 2, 3, 4);

增加了map对象

Set和Map数据解构:

Map

var map = new Map();
// 1. 设置: map.set("name","value")
map.set('a', 'apple');
map.set('b', 'banana');
// 2. 获取:map.get("name")
console.log(map.get("a")); // apple
// 3. 删除之前的map对象:map.delete("name")
map.delete("a");
console.log(map);
// 4. for...in是不能循环map对象,不报错也无反应
for(var name in map){
  console.log(name); // 无输出
}
// 5. 实体map对象的循环输出
for(var name of map){
  console.log(name); // b,banana
}

Set()

Set只存储value值

Set 对象允许你存储任何类型的唯一值,利用set存储唯一值的特点,我们可以进行去重

let list = [1, 2, 2, 3, 4, 5, 5, 5, 4];
console.log(new Set(list)); // {1, 2, 3, 4, 5}

将Set对象转换为数组

let list = [1, 2, 2, 3, 4, 5, 5, 5, 4];
console.log([...new Set(list)]);

Set()

var set = new Set();
set.add(2);
set.add(3);
set.add(4);
console.log(set); // {2, 3, 4}

都有entries()方法(给数组增加索引)

  1. 普通数组:

使用entries()要配合for循环才能拿到里面的索引和对应的值


var arr = [11, 22, 33];
console.log(arr.entries()) //Array Iterator {}
 
for(let n of arr.entries()){
 console.log(n); // (2) [0, 11]  (2) [1, 22]  (2) [2, 33]
}
  1. set():
var set = new Set();
set.add(2);
set.add(3);
set.add(4);
console.log(set); // {2, 3, 4}

var a = set.entries();
console.log(a) //SetIterator {2 => 2, 3 => 3, 4 => 4}
  1. map()

使用entries()要配合next().value使用

var map = new Map();
map.set(3,'a');
map.set(5,'b');
map.set(1,'c');
console.log(map) //Map(3) {3 => 'a', 5 => 'b', 1 => 'c'}
console.log(map.entries().next().value) //[3, 'a']

set和map的区别

  1. set是一种关联式容器,其特性如下:

set以RBTree作为底层容器

所得元素的只有key没有value,value就是key

不允许出现键值重复

所有的元素都会被自动排序

不能通过迭代器来改变set的值,因为set的值就是键

  1. map和set一样是关联式容器,它们的底层容器都是红黑树,区别就在于map的值不作为键,键和值是分开的。它的特性如下:

map以RBTree作为底层容器

所有元素都是键+值存在

不允许键重复

所有元素是通过键进行自动排序的

map的键是不能修改的,但是其键对应的值是可以修改的

模板字符串(${data});

箭头函数;

Promise;

ES6操作数组的方法

[https://blog.csdn.net/qq_58340302/article/details/126429430]

优化项目

1.分隔代码(通过webpack魔法注释):Vue中运用import的懒加载语句以及webpack的魔法注释,在项目进行webpack打包的时候,对不同模块进行代码分割,在首屏加载时,用到哪个模块再加载哪个模块,实现懒加载进行页面的优化。魔法注释/* webpackChunkName:“lodash” */的做用## 标题

在这里插入图片描述

2.提取公共包:使用webpack的splice chunk属性来提取公共包,比如echars

3.图片懒加载(组件v-lazy),精灵图等

4.代码压缩,去除console.log(uglifyjs-webpack-plugin插件),使用cdn服务器等

代码层面

  1. 减少dom操作

  2. 避免eval和function

  3. 减少数组和对象的深层查找

  4. 尽量避免+拼接符

  5. 避免作用域链的查找

页面优化

  1. 减少http请求

  2. 资源合并压缩

  3. 图片懒加载,精灵图

  4. 外部脚本置底,内部脚本异步执行

降低页面加载时间的方法

  1. CDN缓存

  2. 精灵图

  3. 压缩js,css代码

  4. 服务器开启gzip压缩

  5. 页面懒加载,图片懒加载

css精灵图(雪碧图)

面试题博客链接

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值