前端(HTML+CSS+JS+打包+环境+网络)面试题基础八股集合——2023

6,767 阅读56分钟

笔记集合:

前端(HTML+CSS+JS+打包+环境+网络)面试题基础八股集合——2023 - 掘金 (juejin.cn)

TypeScript面试题八股集合——2023 - 掘金 (juejin.cn)

vue2面试题八股集合——2023 - 掘金 (juejin.cn)

vue3面试题八股集合——2023 - 掘金 (juejin.cn)

HTML

如何理解HTML语义化?

1、让人更容易读懂(增加代码可读性)

2、让搜索引擎更容易读懂

通过合理的语义化,可以使得网页结构更加清晰,有助于页面的可读性和可访问性的提高,同时也有利于搜索引擎的爬取和排名,使得网页可以更好地为用户所用。

mate标签有哪些,分别代表什么意思?

"mate"标签是HTML标签之一, 常用于对页面的元数据(metadata)进行描述和定义,包括网页的关键词、页描、作者、字符编码、视口大小、缩放比例等信息。以下是常见的"mate"标签及其含义:

  1. <meta charset="UTF-8">:定义字符编码为UTF-8,确保页面能够正确地显示特殊字符;
  2. <meta name="viewport" content="width=device-width, initial-scale=1.0">:定义视口大小为设备宽度,缩放比例为1,确保在手机等移动设备上显示正常;
  3. <meta name="keywords" content="关键词1, 关键词2, ...">:定义网页的关键词,便于搜索引擎抓取和分析网页主题;
  4. <meta name="description" content="网页描述">:定义网页描述信息,便于搜索引擎显示搜索结果摘要描述;
  5. <meta name="author" content="作者">:定义网页作者信息;
  6. <meta HTTP-EQUIV="refresh" CONTENT="3;URL=http://www.example.com/">:定义网页跳转规则,如每隔3秒自动跳转到指定网址;
  7. <meta name="robots" content="index,follow">:定义搜索引擎对网页的抓取策略,"index"表示允许抓取该网页,"noindex"则表示不允许抓取;"follow"表示跟踪该网页中所有的链接,"nofollow"则表示不跟踪;
  8. <meta name="format-detection" content="telephone=no">:定义是否禁止自动检测页面中的电话号码,避免误触拨打电话。
默认情况下,哪些情况是块级元素、哪些是内联元素?

块级元素(独占一行):display:block/table;有div,h1,h2,table,ul,ol,p等

内联元素(不独占一行):display:inline/inline-block; 有span img input button等

Canvas 与 SVG 区别

Canvas 和 SVG 都是用于在 web 页面上进行图形绘制的技术,它们各自具有不同的特点和适用场景。下面是它们的主要区别:

  1. 基于像素和基于矢量:Canvas 是一种基于像素绘图的技术,它创建的图形是由一个个像素点组成的。而 SVG 则是一种基于矢量图形的技术,它使用数学公式来描述图像,可以任意缩放且不失真。对于需要进行复杂矢量图形绘制的场景,SVG 更适用。而对于需要处理图像、实现像素级别的操作的场景,Canvas 更适用。

  2. 渲染方式:Canvas 是在 HTML5 中新增的一种元素,使用 JavaScript 脚本来进行绘制,绘制区域受到限制,一旦绘制完成就无法再进行修改。而 SVG 是一种矢量图形格式,可以在浏览器中直接嵌入和处理,与 HTML 实现无缝结合,通过修改 SVG 元素的 DOM 树结构,可以对图形进行修改和操作。

  3. 动画绘制:Canvas 通过 JavaScript 实现绘制,可以通过 setInterval、setTimeout 和 requestAnimationFrame 等函数实现动画效果。而 SVG 具有内置的动画效果,支持 SMIL(Synchronized Multimedia Integration Language)动画,也可以通过 JavaScript 实现动画效果。

  4. 兼容性:Canvas 是 HTML5 中新增的元素,对一些老版本的浏览器支持不够完善。而 SVG 可以在现代浏览器和 IE9+ 中正常显示。在处理大量数据时,Canvas 由于绘制速度快,但是浏览器的处理以及渲染运算量会增加,可能会有卡顿等性能问题;而 SVG 的各种鼠标和事件处理,会使得一些浏览器配合页面时产生一些性能和可用性方面的问题。

综上所述,Canvas 更适用于游戏、图像处理、大数据量的动态绘制等场景SVG 更适用于数据可视化、图形编辑和预览等场景。在实际开发中需要根据具体业务场景和要解决的问题来选择合适的技术。

HTML5的新特性?

1、新增标签:语义化标签(hrader、footer等)

2、新增事件:拖放API(drag)

3、新增元素:video和audio元素,提供了播放视频和音频文件的标准方法

4、Canvas绘图;5、SVG绘图; 8、Web Worker;9、Web Storage

CSS

布局

盒模型的宽度如何计算?

image.png

offsetHeight =contentHeight + paddingHeight + borderHeight

clientHeight =contentHeight+paddingHeight

scrollHeight =实际内容Height+paddingHeight

补充:如何让offsetWidth等于100px?

答:加一个box-sizing: border-box

何时使用怪异盒子模型?

框架想要具备栅格系统,肯定要用border-sizing

margin纵向重叠问题
  • margin重叠是指在垂直方向上,相邻的两个元素的margin-topmargin-bottom会发生重叠的情况。

  • 空白内容的 < p > < / p >也会重叠

    两个margin产生折叠的必备条件:

    1、必须处于常规文档流(不能是浮动和定位)的块级盒子,并且处于同一个BFC当中。

    2、没有线盒,没有空隙,没有padding和border将他们分割。

    3、都处于垂直方向相邻的外边距。

margin(top,left,right,bottom)设置负值有何效果?

1、margin-left为负值时,自身元素会向左移动。 2、margin-top为负值时,自身元素会向上移动。 3、margin-right为负值时,自身元素不受影响,但是相邻元素会向左移动。 4、margin-bottom为负值时,自身元素不受影响,但是相邻元素会向上移动。 5、position: absolute时,margin-right和margin-bottom为负值时,自身元素会受影响。

BFC理解和应用

1、是什么

答:Block format context——块级格式化上下文。 是一块独立渲染的区域,内部元素的渲染不会影响边界以外的元素。

2、形成BFC的条件

float不是 none;

overflow不是 visible;

position是 fixed和absolute;

display是 flex,inline-block等

3、BFC常见应用= 清除浮动

一般来说分为以下4种情况:

1、相邻兄弟元素的margin-bottom和margin-top发生重叠,这时候我们可以设置其中一个元素为BFC即可解决。
2、没有内容的元素,自身的margin-top和margin-bottom发生重叠

可以通过以下几种方法解决:

1、元素设置padding或border。 ​ 2、给元素设置一个高度。

3、父元素的margin-top和子元素的margin-top发生重叠,他们发生重叠是因为这两个元素是相邻的,

所以可以通过以下几种方法来解决:

1、为父元素设置padding-top或border-top来分割他们。

​ 2、设置父元素为BFC。 ​

3、父元素和第一个子元素之间添加一个内联元素来进行分割。

4、高度为auto的父元素的margin-bottom和最后一个子元素的margin-bottom发生重叠,他们发生重叠一个原因是他们是相邻的,另一个原因是父元素的高度是不固定的,

那么可以通过以下几种方法来解决:

1、为父元素设置padding-top或border-top来分割他们。

​ 2、设置父元素为BFC。 ​

3、父元素和第一个子元素之间添加一个内联元素来进行分割。

float布局问题(圣杯布局和双飞翼布局),以及claerfix
圣杯布局和双飞翼布局的目的以及如何实现?

目的

三栏布局中间一栏最先加载和渲染(中间内容最重要)

两侧内容固定,中间内容随着宽度自适应

一般用于PC网页

如何实现?

写结构的时候要注意,父元素的的三栏务必先写中间盒子。因为中间盒子是要被优先渲染嘛~并且设置其自适应,也就是width:100%

圣杯布局:

  • 利用浮动和负边距来实现。
  • 父级元素设置左右的 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添加%值时,是根据父元素的宽度来计算的,所以当设置margin-left:-100%后,left刚好被移动到上一行相同位置。而right不需要移动到上一行相同位置,只需要自身在上一行就行,所以只需要设置margin-left为自身的宽度负值后,自动会往上行排。

双飞翼布局:

  • 双飞翼布局相对于圣杯布局来说,左右位置的保留是通过中间列的 margin 值来实现的。本质上来说,也是通过浮动和外边距负值来实现的。
  • 通过设置 margin 负值将其移动到上一行,再利用相对定位,定位到两边。
.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;
}
手写claerfix(清除浮动)
.clearfix:after{
    content: '';
    display: table;
    clear: both;
}
.clearfix{
    *zoom:1;/*兼容IE低版本*/
}
flex布局

常用语法(容器属性):

flex-direction:项目排列方式

justify-content:项目横轴对齐方式

flex-wrap:是否换行

align-content:在项目为多行时需要加flex-wrap:wrap; ,项目纵轴如何对齐(不能控制单行的盒子内位置变换)

align-items(控制容器):项目纵轴如何对齐(能控制单行的盒子内位置变换)

align-self(控制子项):容器子项纵轴如何对齐

如何画三点色子?
.box{
    display:flex;
    justify-content:space-between;
}
.item{
    /*设置点的大小颜色边框等等*/
}
.item:nth-child(2){
    align-self:center;/*第二项居中对齐*/
}
.item:nth-child(3){
    align-self:flex-end;/*第三项尾对齐*/
}
display的属性以及作用?

image.png

display:none和visibility:hidden的区别?
  • 首先是空间占据方面,设置了display:none 样式的元素,在文档流中是不占位置的,而且,浏览器也不会解析这个元素;

  • 而设置了visibility:hidden样式的元素,在文档流中仍然占位,可以理解为,只是把透明度变成了0;

  • 一旦父节点元素应用了 display:none,父节点及其子孙节点元素全部不可见,而且无论其子孙元素如何不屈地挣扎都无济于事。

使用clear清除浮动的原理?
元素的层叠顺序?
CSS3有什么新特性?

css3中新增了一些更加精确的选择器;

  1. 属性选择器:可以根据元素的属性值选择元素。比如:[attr]、[attr=value]、[attr~=value]、[attr|=value]、[attr^=value]、[attr$=value]、[attr*=value]。
  2. 伪类选择器:可以在特定状态下选取元素。比如::hover、:visited、:active、:focus、:first-child、:last-child、:nth-child(n)、:nth-of-type(n)、:not(selector)等。
  3. 伪元素选择器:可以在元素的特定部分选取元素。比如:::before、::after、::first-letter、::first-line等。
  4. 多元素选择器:可以同时选择多个元素。比如:p, h1, li等。
  5. 相邻兄弟选择器:可以选择和某个元素相邻的下一个兄弟元素。比如:h1 + p。
  6. 通用选择器:可以选择所有元素,比如:*。

增加了一些新属性,如border-radius:圆角边框box-shadow:盒子阴影,background-size:背景图片大小;

弹性布局:CSS3提供了flexbox布局模型,使得实现响应式布局更加容易和方便。

还新增了一些动画,如transition:过渡,transform:转换(位移 旋转 缩放)还有animation:动画

伪元素和伪类的区别和作用?
  • 伪类:将特殊的效果添加到特定选择器上。它是已有元素上添加类别的,不会产生新的元素。例如:
a:hover {color: #FF00FF}
p:first-child {color: red}
  • 伪元素:在内容元素的前后插入额外的元素或样式,但是这些元素实际上并不在文档中生成。它们只在外部显示可见,但不会在文档的源代码中找到它们,因此,称为“伪”元素。例如:
p::before {content:"第一章:";}
p::after {content:"Hot!";}
p::first-line {background:red;}
p::first-letter {font-size:30px;}
::before和:after有什么区别?

(1)冒号(:)用于CSS3伪类,双冒号(::)用于CSS3伪元素。 (2)::before就是以一个子元素的存在,定义在元素主体内容之前的一个伪元素。并不存在于dom之中,只存在在页面之中。

Less和sass是什么?我们为什么要使用他?

他们都是 CSS 预处理器,将 CSS 赋予了动态语言的特性,如变量,继承,运算, 函数,LESS 既可以在客户端上运行 (支持 IE 6+, Webkit, Firefox),也可以在服务端运行 (借助 Node.js)。

为什么要使用它们? 结构清晰,便于扩展。 可以方便地屏蔽浏览器私有语法差异。封装对浏览器语法差异的重复处理, 减少无意义的机械劳动。

可以轻松实现多重继承。 完全兼容 CSS 代码,可以方便地应用到老项目中。LESS 只是在 CSS 语法上做了扩展,所以老的 CSS 代码也可以与 LESS 代码一同编译。

定位

absolute和relative分别依据什么定位?

定位元素:absolute, relative ,fixed, body

relative依据自身位置定位,absolute依据最近一层(一层一层向上找父元素)的定位元素定位。

绝对定位和固定定位的元素会脱离文档流吗?

relative相对定位的元素不会脱离文档流;开启fixed绝对定位和absolute固定定位,会使元素脱离文档流

居中对齐有哪些实现方式?

水平居中:

inline元素:text-align: center

block元素:margin: auto

absolute元素: left: 50%+margin-left负值

垂直居中:

inline元素:line-height的值等于 height的值

block元素:margin: auto

absolute元素: top:50%+margin-top负值(知道元素高度的情况下)

absolute元素: transform : translate(-50%,-50%)(不知道元素高度的情况下,对浏览器版本要求高)

absolute元素: top,left,bottom,right都为0 + margin: auto(不知道元素高度的情况下,对浏览器版本无要求)

什么情况下 z-index 会失效?
  1. 问题标签元素的z-index属性值低于父元素 --->提高父标签的z-index值
  2. 问题标签没有设置定位(position)属性 --->浮动元素添加position属性(如relative,absolute等);
  3. 问题标签含有浮动(float)属性。 --->除去浮动
  4. 父标签 position属性为relative --->父标签改为absolute

图文样式

line-height的继承问题

分为三种情况:

1.具体数值(子元素未设置具体行高数值,会自动继承父元素的行高)
2.按比例(子元素未设置行高,父元素行高为1.52

计算:子元素行高会先继承父元素行高的1.52,然后和子元素字体大小(font-size)相乘。

3.百分比(子元素不会直接继承父元素行高,而是等父元素字体大小*行高百分比后在继承)

计算:子元素行高= 父元素字体大小(font-size)*行高百分比。

CSS样式定义的优先级顺序总结

!important>内联样式>ID选择器>类选择器>类型选择器>元素选择器>浏览器默认样式

CSS有哪些属性可以继承?

1、字体系列属性:font、font-family、font-weight、font-size、font-style;

2、文本系列属性: 2.1)内联元素:colorline-height、word-spacing、letter-spacing、 text-transform; 2.2)块级元素:text-indent、text-align;

3、元素可见性:visibility

4、表格布局属性:caption-side、border-collapse、border-spacing、empty-cells、 table-layout;

5、列表布局属性:list-style

6、光标属性:cursor

如何让超出宽度的文字显示为省略号?

text-overflow:ellipsis

如何解决IE6双倍margin的Bug?

使用display:inline

display:none和visibility:hidden的区别?

display:none和visibility:hidden都可以隐藏元素,但它们的行为略有不同。

display:none:将元素完全从页面中删除,元素既不显示也不占据页面空间。它会在DOM结构中删除该元素,因此不会保留元素的空间。

visibility:hidden:隐藏元素,但仍然占据在页面中的位置,元素不会被删除。隐藏后的元素仍在DOM结构中占据空间,因此它保留了隐藏元素的空间。

因此,如果您希望隐藏元素并释放该元素占据的空间,可以使用display:none。而如果您只想隐藏元素但不改变页面布局,可以使用visibility:hidden。

响应式

rem是什么?与vw,vh的区别?

rem是长度单位,是一个相对长度单位

px是绝对长度单位

em是相对长度单位,但是相对于父元素(不常用)

rem是相对长度单位,相对于根元素,所以常用于响应式布局

vw/vh作用?

了解:网页视口尺寸:

image.png

window.screem.height //屏幕高度

window.innerHeight //网页视口高度

document.body.clientHeight //body高度

rem存在一定的弊端,就是存在“阶梯性” 。而vw/vh相对的不是父节点或者页面的根节点。而是由网页视口大小来决定的。

vh:网页视口高度的1/100

vw:网页视口宽度的1/100

vmax 取上面两者中最大的长度;vmin:取上面两者中最小的长度

vw、vh 与 % 百分比的区别

(1)% 是相对于父元素的大小设定的比率,vw、vh 是视窗大小决定的。

(2)vw、vh 优势在于能够直接获取高度,而用 % 在没有设置 body 高度的情况下,是无法正确获得可视区域的高度的,所以这是挺不错的优势。

什么是响应式?

当数据变换的时候,页面发生变化,视图发生变化。

如何实现响应式布局?

1、先使用媒体查询(media-query),根据不同的屏幕宽度设置根元素的font-size

2、后续页面开发中使用基于根元素的rem相对长度单位

怎么理解重构跟重绘?什么场景下会触发?

回流:当我们对 DOM 的修改引发了 DOM几何尺寸的变化(比如修改元素的宽、高或隐藏元素等)时,浏览器需要重新计算元素的几何属性,然后再将计算的结果绘制出来

触发时机:添加删除DOM节点;元素位置发生变化;元素尺寸发生变化,页面一开始渲染

重绘:当我们对 DOM的修改导致了样式的变化colorbackground-color),却并未影响其几何属性时,浏览器不需重新计算元素的几何属性、直接为该元素绘制新的样式

触发时机:颜色修改,文本方向修改,阴影修改

如何减少重构:

  • 对于那些复杂的动画,对其设置 position: fixed/absolute,尽可能地使元素脱离文档流,从而减少对其他元素的影响
  • 如果想设定元素的样式,通过改变元素的 class 类名 (尽可能在 DOM 树的最里层)
  • 避免设置多项内联样式

动画

transition:

/* 应用于1个属性 */
/* 属性值 | 持续时间 */
transition: margin-right 4s;
​
/* 属性值 | 持续时间 | 延迟 */
transition: margin-right 4s 1s;
​
/* 属性值 | 持续时间 | 持续时间 | 动画效果 */
transition: margin-right 4s ease-in-out;
​
/* 属性值 | 持续时间 | 动画效果 | 延迟 */
transition: margin-right 4s ease-in-out 1s;
​
/* 同时应用2个属性*/
transition: margin-right 4s, color 1s;
​
/* 应用于所有属性 | 持续时间 | 动画效果 */
transition: all 0.5s ease-out;
​
/* 全局变量 */
transition: inherit;
transition: initial;
transition: unset;

animation:

/* 持续时间 | 动画效果 | 延迟 | 重复次数 | 方向 | 过渡方式 | 是否暂停 | 动画名 */
animation: 3s ease-in 1s 2 reverse both paused xxx;
​
/* 持续时间 | 动画效果 | 延迟 | 动画名 */
animation: 3s linear 1s xxx;
​
/* 持续时间 | 动画名 */
animation: 3s xxx;
关于CSS3动画

transition 渐变动画(过渡)

transform转变动画(变形+移动)

animation(自定义动画)

ES6

ES6新特性

1、箭头函数的使用

2、class关键字与继承的使用

3、Promise的使用

4、使用关键字 import 导入模块(ES5用require)

5、数据类型添加Symblo,Set,Map

6、let const

script标签中defer和async的区别?

defer 和 async属性都是去异步加载外部的JS脚本文件,它们都不会阻塞页面HTML的解析,其区别如下:

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

没有 deferasync,浏览器会立即加载并执行指定的脚本,之前加载到一半的HTML页面会停止下来,被阻塞加载。

async加载和渲染后续文档元素的过程将和 script.js 的加载与执行并行进行,将script变成异步,当scripet异步解析完成后,如果HTML页面还没有完成解析,又会继续阻塞页面的解析。

defer加载后续文档元素的过程将和 script.js 的加载并行进行,将script变成异步。但是 script.js 的执行要在所有元素解析完成之后,类似于将这个script放在了页面的底部。

总结:async和defer都是异步加载js。不同的是async是js只要一加载完毕就会马上执行 不管html有没有解析完毕。所以它有可能阻塞html解析。而defer要等到html解析完毕之后才执行。所以不会阻塞html解析。

let、const和var的区别?

var存在变量提升;

let const不存在变量提升,只在自己的块级作用域中起作用,存在暂时性死区。

const声明之后要马上赋值,数值变量赋值后补课更改,引用数据类型赋值后可更改。

箭头函数和普通函数的区别?

1、箭头函数都是匿名函数

2、剪头函数本身无this,其this指向父级作用域的this,并且call,bind,apply无法改变this的指向

3、不可以被当做构造函数

4、箭头函数没有参数,直接写一个空括号即可。参数只有一个,也可以省去包裹参数的括号。

5、箭头函数不绑定arguments,取而代之用rest参数...代替arguments对象

6、箭头函数没有prototype,普通函数有

ES6中哪个方法可以实现数组去重?

image.png

ES6中对象新增的方法有哪些?

1、Object.assign()方法用于对象的合并,将源对象的所有可枚举属性,复制到目标对象(target)。

2、Object.is它用来比较两个值是否严格相等,与严格比较运算符(===)的行为基本一致。值和对象类型的值都可以,NAN这种特殊值也可以处理。

3、Object.values方法返回一个数组,成员是参数对象自身的(不含继承的)所有可遍历(enumerable)属性的键值

4、Object.keys方法返回一个数组,成员是参数对象自身的(不含继承的)所有可遍历(enumerable)属性的键名

class和function的区别

相同点:1. 函数作为构造函数

不同点:

  1. class构造函数必须使用new操作符
  2. class声明不可以提升
  3. class不可以用call、apply、bind改变this指向。
Symbol 含义及使用方法

symbol 英文意思为 符号、象征、标记、记号,在 js 中更确切的翻译应该为 独一无二的值。

使用: 作为对象属性 、模拟类的私有方法

如何理解和使用Promise.all和Promise.race

Pomise.all的使用

Promise.all可以将多个Promise实例包装成一个新的Promise实例。同时,成功和失败的返回值是不同的,成功的时候返回的是一个结果数组,而失败的时候则返回最先被reject失败状态的值。

Promise.race的使用

顾名思义,Promse.race就是赛跑的意思,意思就是说,Promise.race([p1, p2, p3])里面哪个结果获得的快,就返回那个结果,不管结果本身是成功状态还是失败状态。

JS

变量类型和计算

为什么0.1+0.2 ! == 0.3,如何让其相等 ?

计算机是通过二进制的方式存储数据的,所以计算机计算0.1+0.2的时候,实际上是计算的两个数的二进制的和。0.1的二进制是0.0001100110011001100...(1100循环),0.2的二进制是:0.00110011001100...(1100循环),这两个数的二进制都是无限循环的数。那JavaScript是如何处理无限循环的二进制小数呢?

其实就是保留53位有效数字,剩余的需要舍去,遵从“0舍1入”的原则。

要想等于0.3,就要把它进行转化:

(n1 + n2).toFixed(2) // 注意,toFixed为四舍五入

toFixed(num) 方法可把 Number 四舍五入为指定小数位数的数字。

Object.is() 与比较操作符 “===”、“==” 的区别?

使用双等号(==)进行相等判断时,如果两边的类型不一致,则会进行强制类型转化后再进行比较。

使用三等号(===)进行相等判断时,如果两边的类型不一致时,不会做强制类型准换,直接返回 false。

使用 Object.is 来进行相等判断时,一般情况下和三等号的判断相同,它处理了一些特殊的情况,比如 -0 和 +0 不再相等,两个 NaN 是相等的。

对于 <> 比较符

如果两边都是字符串,则比较字母表顺序:

'ca' < 'bd' // false
'a' < 'b' // true
复制代码

其他情况下,转换为数字再比较:

'12' < 13 // true
false > -1 // true
什么是 JavaScript 中的包装类型?

在 JavaScript 中,基本类型是没有属性和方法的,但是为了便于操作基本类型的值,在调用基本类型的属性或方法时 JavaScript 会在后台隐式地将基本类型的值转换为对象,如:

const a = "abc";
a.length; // 3
a.toUpperCase(); // "ABC"
js 函数中的 arguments是什么?

arguments 是一个对象,不是一个 Array 。使用arguments 对象在函数中引用函数的参数。

forEach和map的区别,可以改变原数组吗?

1、forEach()方法没有返回值,而map()方法有返回值。

2、forEach遍历通常都是直接引入当前遍历数组的内存地址,会改变原数组,生成的数组的值发生变化,当前遍历的数组对应的值也会发生变化。类似于浅拷贝

3、map遍历的后的数组通常都是生成一个新的数组新的数组的值发生变化,当前遍历的数组值不会变化。 地址和值都改变 类似于深拷贝

4、总的来说 map 的速度大于forEach,性能上来说for>forEach>map

什么时候用href,什么时候用src

src指向的内容会嵌入到文档中当前标签所在的位置。常用的有:img、script、iframe。

href是Hypertext Reference的缩写,表示超文本引用。用来建立当前元素和文档之间的链接。href 目的不是为了引用资源,而是为了建立联系,让当前标签能够链接到目标地址。常用的有:link、a。

总结: src用于替换当前元素(比如:引入一张图片);href用于在当前文档和引用资源之间建立联系。

link和@import的区别

两者都是外部引用 CSS 的方式,但是存在一定的区别:

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

(2)link引用CSS时,在页面载入时同时加载;@import需要页面完全载入以后再加载。

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

(4)link支持使用Javascript控制DOM改变样式;而@import不支持。

typeof能判断那些类型?

能判断所有值类型,函数,以及引用类型(无法细分引用类型为数组还是对象)

何时使用===/==?

在 JavaScript 中,使用双等号(==)和三等号(===)都可以用于比较两个值的相等性。但是它们之间还是有一些区别的。

使用双等号(==)比较时,如果类型不同,会进行类型转换,将两个值转换成同样的类型进行比较;而使用三等号(===)比较时,如果类型不同,会直接返回 false,不会进行类型转换。因此,我们可以根据情况选择使用不同的比较符。

以下是两者使用的场景:

  1. 当我们想要比较两个值的值和类型是否完全相等时,应该使用三等号(===),例如:
const a = 1;
const b = "1";
console.log(a === b); // false
  1. 当我们想要比较两个变量的值是否相等,且不考虑类型时,可以使用双等号(==),例如:
const a = 1;
const b = "1";
console.log(a == b); // true

需要注意的是,由于双等号存在类型转换,因此可能会存在隐式类型转换导致的一些问题,比如比较非布尔类型的值时,可能会出现一些奇怪的结果。因此,在实际开发中,建议尽可能使用三等号(===),确保比较的准确性。

值类型和引用类型区别?

存储位置(栈/堆),存储内容(数/地址)

深拷贝浅拷贝的区别?手写深拷贝?

浅拷贝,如果属性是基本类型,拷贝的就是基本类型的值。如果属性是引用类型,拷贝的就是内存地址。

深拷贝,开辟一个新的栈,两个对象属完成相同,但是对应两个不同的地址,修改一个对象的属性,不会改变另一个对象的属性。

function deepClone(obj={}){
    if(typeof(obj)!==object || obj == null){
        //obj是null,或者不是对象和数组则直接返回
        return obj;
    }
    //初始化返回结果
   let result;
    //判断是数组还是对象
    if(obj instanceof Array){
        result = [];
    }else{
        result = {};
    }
    
    for(let key in obj){
        //保证key不是原型的属性
        if(obj.hasOwnProperty(key)){
            //递归调用!!!
            result[key] =  deepClone(obj[key])
        }
    }
    return result;
}
扩展运算符的作用及使用场景?

对象的扩展运算符(...)用于取出参数对象中的所有可遍历属性,拷贝到当前对象之中。(浅拷贝)

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

遍历Map/Set/generator数组/字符串:用for...of...(可迭代),得到value

遍历对象/数组/字符串:用for...in...(可枚举数据),得到key

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

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

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

补充for await...of的作用 : 用于遍历多个Promise

遍历数组,for和forEach哪个快?

for更快;因为forEach每次都要创建一个函数来调用,而for不会创建函数,函数需要独立的作用域,会有额外开销

JS严格模式有什么特点?

①全局变量必须声明

②禁止this指向windows

③函数参数名称不能重复

④禁止使用with

⑤创建eval作用域(单独作用域)

js 中const真的不能修改吗?

const定义的基本类型不能改变,但是定义的引用类型中的 数组 与 对象 可以通过修改对象属性改变。 const使用建议:不要使用const定义 数组 或 对象 作为常量。

原型和原型链

如何判断一个变量是不是数组?

XX instanceof Array ; Array.isArray() ; toString.call()

instanceof 运算符用于检测构造函数的 prototype 属性是否出现在某个实例对象的原型链上。instanceof 可以准确地判断复杂引用数据类型,但是不能正确判断基础数据类型

补充:typeof与instanceof的区别?

①返回结果类型不同:typeof会返回一个变量的基本类型,instanceof返回的是一个布尔值

②判断范围不同:instanceof 可以准确地判断复杂引用数据类型,但是不能正确判断基础数据类型;而typeof 也存在弊端,它虽然可以判断基础数据类型(null 除外),但是引用数据类型中,除了function 类型以外,其他的也无法判断

class的原型本质怎么理解?

①原型:所有的class都有显示原型,每个实例都有隐式原型,实例的隐式原型等于对应class的显示原型,非基本属性的class的隐式原型等于其继承的class的显示原型。

②原型链:每一个对象都有一个隐式原型叫__proto__,它的指向是构造函数的原型对象。当查找某个属性或方法时,先从自身上查找,没有找到会沿着__proto_找到构造函数的原型对象,仍然没有找到会继续沿着__proto__向上查找到它构造函数原型对象的原型对象,直到找到顶级对象object为null,由此形成的链条为原型链。

ES5、ES6 如何实现继承?

ES5:①原型链继承 ②构造函数继承 ③组合继承 ④寄生组合继承

ES6:ES6 中引入了 class 关键字, class 可以通过 extends 关键字实现继承。ES6的继承中super是用来①调用父类函数 ②指向父类的原型

JS构造函数new的过程

用new操作符创建对象时发生的事情:

(1)创建一个新对象;

(2)将构造函数的作用域赋给新对象(因此this就指向了这个新对象);

(3)执行构造函数中的代码(为这个新对象添加属性和方法);

(4)返回新对象;

作用域和闭包

1.1自由变量如何取值?

自由变量的查找,是在函数定义的地方,向上级作用域查找,不是在执行的地方!!! 一个变量在当前作用域中那个没有定义,但是被使用了,系统则会想上级作用域一层一层依次寻找直到找到为止;如果到全局作用域都没有找到,则报错xx is not defined。

this的不同应用场景,如何取值?

this取值由函数执行的位置地方决定,先查找自己的块级作用域,然后再向上查找。

一共分为一下4种情况:

第一种是函数调用模式,当一个函数不是一个对象的属性时,直接作为函数来调用时,this 指向全局对象。

第二种是方法调用模式,如果一个函数作为一个对象的方法来调用时,this 指向这个对象。

第三种是 apply 、 call 和 bind 调用模式,这三个方法都可以显示的指定调用函数的 this 指向。其中 apply 方法接收两个参数:一个是 this 绑定的对象,一个是参数数组。call 方法接收的参数,第一个是 this 绑定的对象,后面的其余参数是传入函数执行的参数。也就是说,在使用 call() 方法时,传递给函数的参数必须逐个列举出来。bind 方法通过传入一个对象,返回一个 this 绑定了传入对象的新函数。这个函数的 this 指向除了使用 new 时会被改变,其他情况下都不会改变。

第四种是构造器调用模式,如果一个函数用 new 调用时,函数执行前会新创建一个对象,this 指向这个新创建的对象。

bind、call、apply 区别?

call、apply、bind作用是改变函数执行时的上下文,简而言之就是改变函数运行时的this指向

function fn(...args){
    console.log(this,args);
}
let obj = {
    myname:"张三"
}
fn(1,2) // this指向window
fn.apply(obj,[1,2]); // this会变成传入的obj,传入的参数必须是一个数组;
fn.call(obj,1,2); // this会变成传入的obj,传入的参数必须是一个数组;
const bindFn = fn.bind(obj); // this 也会变成传入的obj ,bind不是立即执行需要执行一次
bindFn(1,2) // this指向obj

applycallbind三者的区别在于:

  • 三者第一个参数都是this要指向的对象,如果如果没有这个参数或参数为undefinednull,则默认指向全局window
  • 三者都可以传参,但是apply是数组,而call是参数列表,且applycall是一次性传入参数,而bind可以分为多次传入
  • bind返回绑定this之后的函数,便于稍后调用,applycall 则是立即执行
3、谈谈对闭包的理解?应用场景

闭包定义 : ①是个函数②这个函数有权访问另一个函数作用域中的变量

产生闭包的条件:1.函数嵌套2.内部函数引用了外部函数的数据(变量/函数)。

闭包的应用:隐藏数据,只提供api

image.png

注意:闭包里面的数据永远常驻内存,不会被销毁

异步

同步和异步的区别是什么?

同步:会阻塞代码的执行,异步:基于JS单线程,不会阻塞代码的执行。

进程和线程的区别,进程和线程的通信方式,进程挂了会不会影响其它进程,线程挂了进程会不会挂?

进程:是cpu分配资源的最小单位;(是能拥有资源和独立运行的最小单位)

线程:是cpu调度的最小单位;(线程是建立在进程的基础上的一次程序运行单位,一个进程中可以有多个线程)

放在浏览器中,每打开一个tab页面,其实就是新开了一个进程,在这个进程中,还有ui渲染线程,js引擎线程,http请求线程等。 所以,浏览器是一个多进程的。

进程间的通信方式:

无名管道( pipe )、命名管道 (FIFO)、信号量、共享内存、消息队列

线程之间的通信方式:

锁机制、信号量机制、信号机制

如果一个进程挂了,可能会影响到其它进程,具体影响取决于该进程所占用的资源和系统的处理能力。一般来说,进程挂了可能会导致系统资源占用不当,或者占用的资源不能正常释放,从而影响其它进程的运行。

进程中的某个线程挂了,其它线程不会受到影响,进程也不会挂掉。

JS是单线程的,如何开启多进程?

首先JS是单线程语言,所以无法开启多线程,可以通过webWorker实现多进程。

Web Worker 的作用,就是为 JavaScript 创造多线程环境,允许主线程创建 Worker 线程,将一些任务分配给后者运行。在主线程运行的同时,Worker 线程在后台运行,两者互不干扰。等到 Worker 线程完成计算任务,再把结果返回给主线程。

前端使用异步的场景有哪些?

1、网络请求 2、定时任务

请描述 event loop(事件循环/事件轮询)的机制,可画图

event loop是异步回调的实现原理。

首先计算机执行我们的代码是一行一行从上到下的执行,每执行一行话,就将其放置到call stack调用,执行完就进行销毁。

然后如果代码中遇到异步操作时,会将其进行“记录”(Promise这些放入微任务队列中,setTimeout,ajax这些放入宏任务队列);对于宏任务队列,等待时机(定时到了,网络请求完成)则加入到callback Queue。

当call stack中没有代码时,会先执行微任务队列,然后尝试渲染DOM,

最后会开启event loop事件循环机制,不断的查找callback Queue,如果callback Queue中有,则移动到Call Stack执行。

然后继续进行循环查询(像永动机一样)。

宏任务有哪些?微任务有哪些?和DOM渲染的关系

JavaScript 运行时的事件循环机制中,任务分为宏任务(macro task)和微任务(micro task)。

常见的宏任务有:

  • setTimeout 和 setInterval 的回调函数
  • DOM 事件
  • XMLHttpRequest 中的readystatechange事件
  • requestAnimationFrame 中的回调函数
  • I/O 操作和网络请求的回调函数
  • Node.js 中的文件读写操作的回调函数
  • Node.js 中的进程事件

常见的微任务有:

  • Promise 的回调函数(then、catch、finally)
  • MutationObserver 监听函数
  • process.nextTick 回调函数
  • Object.observe 的回调函数
promise实现异步的原理?

我们知道Promise一共由三种状态: Penning、Fulfilled、Rejected, 而状态是不可逆的,Promise正是通过修改状态的方式,在合适的时机触发相应状态的回调来达到处理异步的目的。通过then的链式调用也避免了回调地域的问题。

promise是如何链式调用的?
  • then 方法要链式调用那么就需要返回一个 Promise 对象
  • then 方法里面 return 一个返回值作为下一个 then 方法的参数,如果是 return 一个 Promise 对象,那么就需要判断它的状态
Promise的三种状态,如何变化?
Promise 和 async/await 的异常处理?
promise.catch(e=>{ // TODO sth with e })

    async function test(){

          try{ await promise; }

          catch(e){ // TODO sth with e } }
JavaScript脚本延迟加载的方式有哪些?

defer 属性async 属性使用 setTimeout 延迟方法让 JS 最后加载

JS-Web-API

DOM

DOM属于哪种数据结构

DOM操作的常用API

创建:createElement

插入:appendChild

删除:removeChild

获取子节点:childNodes

获取子节点:parentNodes

attribute和property(都是属性)的区别

两者都有可能引起DOM重新渲染

property : 修改对象属性,不会体现到html结构中

attribute : 修改html属性,会改变html结构

如何识别浏览器的类型

navigator.userAgent

事件

什么是事件冒泡?什么是事件代理?

事件冒泡和事件代理都是JavaScript中处理事件的机制。

事件冒泡指的是当用户触发某个元素的事件时,该事件会先被触发该元素上,然后再逐级往上层元素传递,直至达到文档节点。简单来说,就是事件从子元素向父元素冒泡传递的过程。

事件代理,又称事件委托,是利用了事件冒泡机制,把事件绑定到父元素上,然后通过判断事件的target属性,来确定触发事件的元素是否是我们需要处理事件的元素,从而实现事件处理的目的。这种机制能够减少事件处理程序的数量,避免了为每一个节点添加事件处理程序,从而节省内存和提高程序的效率。

下面是一个例子来理解事件代理的思想:

假设有一个列表,列表中很多项都需要添加一个点击事件,这个事件是对每个列表项的删除操作,假如我们使用事件冒泡机制,那么每次点击操作都需要遍历所有的列表项,性能会非常低下。但是如果我们把这个点击事件绑定到列表的父元素上,然后逐级冒泡,并在父元素上判断点击事件是否来源于列表项,只对列表项进行删除操作,这样就能够实现事件代理,从而降低处理事件的数量,提高程序性能。

<div id="list" onclick="handleClick(event)">
  <ul>
    <li>item 1</li>
    <li>item 2</li>
    <li>item 3</li>
  </ul>
</div>

function handleClick(event) {
  if(event.target.tagName === 'LI') {
    event.target.parentElement.removeChild(event.target);
  }
}

在这个例子中,我们把点击事件绑定到父元素<div>上,并在父元素上通过判断点击事件是否来自列表项来实现删除操作,这就是事件代理机制的应用。

ajax

手写一个简易的ajax
  1. 创建 xhr 对象
  2. 准备发送请求
  3. 监听事件,处理响应
  4. 发送请求
function ajax(url){
    return new Promise((resolve,rejecte)=>{
        let xhr = new XMLHttpRequest();
        xhr.open("get",url,true)
        
        xhr.onreadstatechange = function(){
            if (xhr.readState === 4){
                if(xhr.status === 200){
                    resolve()
                }else{
                    rejecte()
                }
            }
        }
        
        xhr.send(null)
    })
}
Ajax Fetch Axios的区别?

三者都是网络请求,但是维度不同。

  • Ajax:是一种技术统称

  • Fetch:是一个具体的浏览器原生API,用于网络请求;它和xmlhttpRequest是一个级别的,但是其语法更加简洁,更加易用,并且支持Promise

  • Axios:是一个第三方库。内部可以通过XMLHttpRequest和Fetch来实现

跨域常用的实现方法?
  1. JSONP:通过动态创建 script 标签,向其他域名发起 GET 请求,从而获得数据。

  2. CORS:在服务器端设置响应头,允许其他域名的请求访问数据。

  3. 代理:在自己的服务器端设置代理,将跨域请求转发到其他域名的服务器上,从而获得数据。

  4. PostMessage:使用 HTML5 新增的 API,在不同的窗口之间进行安全的跨域通信。

  5. WebSocket:使用 HTML5 新增的 API,实现全双工通信,从而避免跨域问题。

存储

描述cookie,localStorage,sessionStorage的区别?

①容量 :cookie(<4K),localStorage 和 sessionStorage(<5M)。

②API易用性:cookie(document.cookie),localStorage 和 sessionStorage(setitem getitem)。

③是否跟随http请求发送出去:cookie(跟随),localStorage 和 sessionStorage(不跟随)。

如何检测内存泄漏?内存泄露的几种场景?

检测:

image.png

场景:①意外的全局变量、全局函数 ②定时器 ③没有清理对DOM元素的引用④自定义事件的应用,组件未被清除⑤不合理的闭包

JS垃圾回收机制用的什么算法?

什么是垃圾回收: JavaScript代码运行时,需要分配内存空间来储存变量和值。当变量不在参与运行时,就需要系统收回被占用的内存空间,这就是垃圾回收。只要一个函数执行完了,里面的函数都应该被删除

算法

清除标记: 当变量进入执行环境时,就标记这个变量“进入环境”,被标记为“进入环境”的变量是不能被回收的,因为他们正在被使用。当变量离开环境时,就会被标记为“离开环境”,被标记为“离开环境”的变量会被内存释放

引用计数(之前):跟踪记录每个值被引用的次数。

存在问题:循环引用例如:obj1obj2通过属性进行相互引用,两个对象的引用次数都是2。当使用循环计数时,由于函数执行完后,两个对象都离开作用域,函数执行结束,obj1obj2还将会继续存在,因此它们的引用次数永远不会是0,就会引起循环引用。

闭包是内存泄露吗?

严格来说不是,内存泄露是指在非预期情况下,数据的内存未被释放。但是闭包是符合预期的。

开发环境

Git

以下是Git常用的命令:
  1. 初始化一个仓库:git init

    查看分支:git branch

    将已修改或未跟踪的文件添加到暂存区:git add [file] 或 git add .

    提交至本地仓库:git commit -m "提及记录xxxx"

    本地分支推送至远程分支:git push origin ...

    查看当前工作目录和暂存区的状态: git status

    查看提交的日志记录: git log

    从远程分支拉取代码:git pull origin ...

    合并某分支(xxx)到当前分支: git merge xxx

    切换到分支xxx(分支名字):git checkout xxx

    文件行为撤销一次(文件名字):git checkout xxx

    创建分支xxx并切换到该分支:git checkout -b xxx

    删除分支xxx:git branch -d xxx

    将当前分支到改动保存到堆栈中:git stash

    恢复堆栈中缓存的改动内容:git stash pop

    查看某次提交的内容:git show xxx

使用Git命令行解决冲突
1.  明确合并时哪些文件发生冲突 (当前分支为dev1)

-   执行命令:git merge 分支名 有冲突时会提示哪些文件有冲突
-   代码冲突:会停留在MERGING状态

image.png

2. 查看不同分支代码的差异化

-   执行命令:cat 冲突文件

image.png img

3. 修改冲突文件(合并代码)

-   执行命令:vim 冲突文件

image.png

通过vim编辑器,删除冲突文件中不需的内容后:

image.png

4. 提交修改后的冲突文件

-   执行命令:git add 修改后的冲突文件 先添加到暂存区
-   执行命令:git commit -m '消息' 再提交到本地Git

image.png

**5. 推送到Git远程仓库**

-   执行命令:git push

image.png

webpack和babel

前端代码为什么要进行构建和打包?

在开发后完成的这个合并的过程就是打包,可以减少了http请求数量,让我们的页面加载和显示更快。

Babel和webpack的区别?

babel是一个JS编译器,用来将ES6/ES7等语法转换为ES5语法(浏览器不认识的语法编译成浏览器认识的语法),从而能够使代码在大部分浏览器中运行。但是babel转换语法时有一些新的api是不转化的,比如promise、Object.assign等,所以babel还提供了很多插件,如babel-polyfill。

webpack是一个打包工具,打包js、css、图片、html等,它可以分析整个项目的文件结构,确认文件之间的依赖,将文件合成、压缩、加入hash等,生成最终项目文件。webpack把所有文件当成模块,但是webpack内置默认的加载器是处理js的,如果要处理其他类型的文件则需要引入不同的loader加载器,用来转化其他文件进行编译打包。webpack通过使用babel-loader使用Babel。

总结:

webpack和babel通常配合起来使用

babel是js编译工具,能将es6或者一些特殊语法做一些转换,只做文件转义,不做文件整合。

webpack是一个打包工具,内置只能处理js,但是它可以加载很多的loader处理css,img,ts,vue等其他文件,最终输出js文件。

webpack通过使用babel-loader使用Babel

webpack如何实现懒加载?

使用import()结合异步组件和异步路由

webpack的热更新原理?

Webpack的热更新又称热替换(Hot Module Replacement),缩写为HMR。这个机制可以做到不用刷新浏览器而将新变更的模块替换掉旧的模块。

webpack打包过程
  • 解析入口文件,生成AST树,遍历所有依赖项,收集依赖;
  • 递归解析所有的依赖项,生成依赖关系图;
  • 使用依赖关系图,生成一个可以在浏览器运行的JS文件;
  • 输出到指定文件夹下;
loader和plugin的区别?

在运行时机上,loader 运行在打包文件之前plugin则是在整个编译周期都起作用。

loader是文件加载器,能够加载资源文件,并对这些文件进行一些处理,诸如编译、压缩等,最终一起打包到指定的文件中;

plugin扩展了更多的功能;赋予了webpack各种灵活的功能,例如打包优化、资源管理、环境变量注入等,目的是解决 loader无法实现的其他事。

linux命令

常用的Linux命令:
  1. ls:列出当前目录下的文件和文件夹。
  2. cd:进入指定目录。
  3. pwd:显示当前所在的目录。
  4. mkdir:创建一个新的目录。
  5. rm:删除文件或目录。
  6. cp:将文件或目录复制到另一个位置。
  7. mv:将文件或目录移动到另一个位置。
  8. cat:查看文件的内容。
  9. nano:在命令行中编辑文件。
  10. touch:创建一个新的空文件。
  11. chmod:修改文件或目录的权限。
  12. chown:修改文件或目录的所有者。
  13. ps:列出当前正在运行的进程。
  14. kill:终止正在运行的进程。
  15. top:显示当前系统资源的使用情况。

运行环境

页面加载

从输入 url 到渲染出页面的整个过程

①下载资源:各个资源类型,下载过程。

  1. 浏览器判断内容
  2. 查找缓存
  3. DNS 解析:首先需要将 URL 解析成 IP 地址。浏览器会先查找本地 DNS 缓存,如果没有找到则向本地 DNS 服务器发送请求,获取目标服务器的 IP 地址。
  4. TCP 连接:通过 IP 地址和端口号建立 TCP 连接,发起三次握手。
  5. 发送 HTTP 请求:使用 HTTP 协议向目标服务器发送请求,请求中包含请求方法、请求头、请求体等信息。
  6. 服务器处理请求并返回响应:服务器接收到请求后,根据请求内容进行处理,并返回响应。响应中包含状态码、响应头、响应体等信息。
  7. 浏览器解析响应内容:浏览器接收到响应后,根据响应头中的内容判断响应类型,如果是 HTML 页面,则开始解析 HTML 文档。

②渲染页面:

  1. 构建 DOM 树:浏览器解析 HTML 文档,根据 HTML 标记构建出 DOM 树。
  2. 构建 CSSOM 树:浏览器解析 CSS 样式表,构建出 CSSOM 树。
  3. 合并 DOM 树和 CSSOM 树:将 DOM 树和 CSSOM 树合并,生成渲染树。
  4. 布局和绘制:根据渲染树中的信息进行布局和绘制,生成位图并显示在屏幕上。遇到
  5. 网络资源加载:在上述过程中,如果页面中包含了其他资源(如图片、脚本、样式表等),则需要再次向服务器发起请求,获取这些资源并进行渲染。
load和 DOMContentLoaded 的区别
  • load:资源全部加载完才能执行,包括图片。
  • DOMContentLoaded:DOM 渲染完成即可,图片可能尚未下载。

性能优化

前端常见性能优化方案

①加载优化:

  • 减少资源体积:压缩代码。
  • 减少访问次数∶合并代码、SSR服务器端渲染、緩存。
  • 使用更快的网络:CDN。

②渲染优化:

  • 对 DOM 查询进行缓存。
  • 节流 throttle 防抖 debounce。
  • 懒加载
  • 频繁 DOM 操作,合并到一起插入 DOM 结构。
  • CSS 放在 head,JS 放在 body 最下面。
  • 尽早开始执行JS,用 DOMContentloaded 触发。
防抖和节流是什么?手写一个

两者都是优化高频率执行JS代码的一种手段。

防抖( debounce) :n秒后在执行该事件,若在n秒内被重复触发,则重新计时。

使用场景:监听一个输入框,文字改变后触发change事件

存在问题:直接监听keyup,会频繁的触发change事件

防抖:用户输入结束或暂停时,才触发change事件

function debounce(fn,delay=500){
 let  timer= null;
 return function(){
     if (timer){
         clearTimeout(tinmer)
     }
     timer = setTimeout(()=>{
         fn.apply(this,arguments)
         timer = null
     },delay)
 }
}
const input1 = document.getElementId('input1')
input1.addEventListener("keyup",debounce(function (e){
  console.log(e.target);
  console.log(this.value);
},600))

节流(throttle) :在一段时间内,只执行一次。

使用场景:拖拽某个元素,要随时知道该元素被拖拽的位置

存在问题:直接监听使用drag拖拽,会频繁的触发change事件

节流:无论拖拽速度多快,都每100ms触发一次

function throttle(fn,delay = 100){
 let timer = null
 return function(){
     if (timer) return 
     timer = setTimeout(()=>{
         fn.apply(this,arguments)
         timer = null
     },delay)
 }
}
const div1 = document.getElementId('div1')
div1.addEventListener("dray",throttle(function (e){
  console.log(e.offsetX, e.offsetY);
},600))

安全

Web前端常见的安全攻击方式和预防
攻击方式

XSS跨站脚本攻击:黑客将JS代码插入到网页内容中,渲染时执行JS代码

跨站请求伪造

预防
  • XSS 预防:替换特殊字符串
  • CSRF 预防:使用 post 接口、增加验证,如:密码、短信验证码等。

TCP(网络连接)

这一章内容与下一章内容是存在关系的,我们要先建立网络的连接,确保双方都有发消息的能力,才能进行内容传输。

请描述TCP三次握手和四次挥手
TCP/IP的体系结构

image.png

TCP(稳定传输)三次握手和四次挥手

握手是连接

客户端发包,服务端接收:发送,请求连接的请求

服务端接收包,客户端接收:回复,是否同意连接请求的信息

客户端发包,服务端接收:发送,准备发送请求信息

挥手是断开

客户端发包,服务端接收:请求已结束

服务端接收包,客户端接收:知道请求已经结束

但是中间依旧存在服务端给客户端发送数据信息

服务端接收包,客户端接收:发送完成

客户端发包,服务端接收:我已知晓发送完成(不能少)

UDP协议(不稳定传输,但是效率高)无连接无断开

应用:视频会议,语音通话

HTTP和WebSocket (传输内容)

状态码

1XX :服务器接收到请求

2XX:请求成功,如200

3XX:重定向,如302

4XX:客户端错误,404

5XX :服务端错误,500

常见状态码

200 成功 ;301永久重定向(配合 location,浏览器自动处理);302临时重定向(配合 location,浏览器自动处理);304 资源未被修改;403 无权限;404资源未找到;500服务器错误;504网关超时。

HTTP协议和UDP协议有什么区别?

HTTP协议在应用层,TCP和UDP协议在传输层,严格来说应该拿TCP和UDP进行比较。

HTTP跨域请求时为何发送options请求

options请求是跨域之前的预检查,浏览器自行发起,不影响实际功能。

什么是HTTP? HTTP 和 HTTPS 的区别?

HTTP协议是超文本传输协议,信息是明文传输的,HTTPS则是具有安全性的SSL加密传输协议;

HTTP和HTTPS协议的主要区别如下:

  • HTTPS协议需要CA证书,费用较高;而HTTP协议不需要;
  • 使用不同的连接方式,端口也不同,HTTP协议端口是80,HTTPS协议端口是443;
  • HTTP协议连接很简单,是无状态的;HTTPS协议是有SSL和HTTP协议构建的可进行加密传输、身份认证的网络协议,比HTTP更加安全。
什么是HTTPS中间人攻击?如何预防?

在HTTPS传输过程中,存在非对称加密和对称加密两个加密过程,中间人攻击就是在非对称加密过程中,黑客传入自己的公钥,导致服务端用假的公钥加密了数据

HTTP协议1.0 1.1 2.0有什么区别?

HTTP1.0:HTTP/1.0规定浏览器和服务器保持短暂的连接。浏览器的每次请求都需要与服务器建立一个TCP连接,服务器处理完成后立即断开TCP连接(无连接),服务器不跟踪每个客户端也不记录过去的请求(无状态

HTTP1.1:增加缓存策略;默认使用持久连接Connection:keep-alive,一次TCP连接多次请求,支持新方法 PUT DELET等。(目前最常用)

HTTP2.0:可压缩header;多路复用,一次TCP连接中,可以多个人HTTP并行请求;实现了头信息压缩。采用二进制格式传输数据,而非 HTTP/1.x 的文本格式,二进制协议解析起来更高效

为什么可以使用websocket解决跨域?

因为浏览器支持websocket通信,而websocket没有浏览器跨域的限制(需要服务端支持websocket相关的协议)

token和cookie的区别?

cookie:HTTP标准;存在跨域限制问题,配合session使用

token:无标准,是自行存储,无跨域限制;用于JWT

session和JWT分别适合哪些场景?

Session:有严格要求管理用户信息的需要(保密、快速禁封)

JWT:没有特殊要求

HTTP 和WebSocket 的区别?

image.png

相同点: 都是一样基于TCP的,都是可靠性传输协议。都是应用层协议。

联系: WebSocket在建立握手时,数据是通过HTTP传输的。但是建立之后,在真正传输时候是不需要HTTP协议的。

区别

1、WebSocket是双向通信协议,模拟Socket协议,可以双向发送或接受信息,而HTTP是单向的;

2、WebSocket是需要浏览器和服务器握手进行建立连接的,而http是浏览器发起向服务器的连接。

注意:虽然HTTP/2也具备服务器推送功能,但HTTP/2 只能推送静态资源,无法推送指定的信息。

http method

传统方法
  • get 获取服务器的数据。
  • post 向服务器提交数据。
现在的方法
  • get 获取数据
  • post 新建数据
  • patch/put 更新数据
  • delete 删除数据

Restful API

什么是Restful API?

是一种基于 HTTP 协议,符合 REST 风格的 Web API 设计规范。它通过对资源的表现层(Representation)进行操作来实现客户端和服务器之间的数据交互。

  • 传统 API 设计:把每个 url 当作一个功能。

  • Restful API 设计:把每个 url 当作一个唯一的资源。

    如何设计成一个资源?

    ①尽量不使用url参数

    img

    ②用method表示操作类型

    img

headers

http常见的header有哪些?

请求头(request headers)

Accept 浏览器可接收的数据格式

Accept-Encoding 浏览器可接收的压缩算法,如gzip

Accept-Language 浏览器可接收的语言,如zh-CN

Connection: keep-alive 一次TCP连接重复使用

cookie 每次同域请求都会带

Host: 请求的域名是什么(网址)

User-Agent(UA) 浏览器信息

Content-type 发送数据的格式 如,application/json

回复头

Content-type 返回数据的格式 如,application/json

Content-length 返回数据的大小,多少字节

Content-Encoding 返回数据的压缩算法,如 gzip

Set-Cookie 设置Http Cookie

Cache-Control 控制强制缓存的逻辑

缓存头

Cache-Control

Expires

Last-modified

Etag

自定义header

例如:axios请求在header请求头加入自定义信息

使用请求拦截器

缓存策略

什么是缓存?

Web 页面的静态资源(如img图片、css样式表、脚本等)保存到客户端(如浏览器)中,以便下次访问时可以直接从客户端获取,加快页面的加载速度。

为什么需要缓存?
  1. 加快页面加载速度:当用户访问一个网站时,浏览器需要下载网站的所有资源才能显示页面。如果这些资源已经被缓存到客户端,那么用户再次访问该网站时,就可以直接从客户端获取缓存的资源,加快页面的加载速度。
  2. 减少网络请求的数量和体积:如果每次访问 Web 页面时都需要从服务器下载所有资源,那么将会消耗大量的网络流量,影响用户体验。而如果将这些资源缓存到客户端,那么就可以在一定程度上减少网络传输,节约网络资源。
  3. 减轻服务器压力:如果所有用户都从服务器下载资源,那么服务器的压力将会非常大。而如果将这些资源缓存到客户端,那么可以减轻服务器的负担,提高服务器的性能和稳定性。
  4. 网络请求存在不稳定性,加剧了页面加载的不稳定性
如何实现缓存

缓存的计算方式:静态资源加hash后缀(根据文件内容计算),文件内容不变,则hash不变,则url不变。

url和文件内容不变,则返回304

浏览器中缓存的位置一般是硬盘或内存中,具体位置由浏览器的缓存策略和具体实现决定。

http缓存策略(强制缓存+协商缓存)
  1. 强缓存(Cache-Control 和 Expires(不使用了)):强缓存表示资源不需要向服务器验证,可以直接从缓存中获取。常见的强缓存策略包括使用 Cache-Control 和 Expires 头字段来控制缓存的时间。其中,Cache-Control 包含 max-age 和 no-cache 等指令,max-age 表示缓存时间,no-cache 表示缓存需要重新验证;Expires 则是一个时间戳,表示缓存过期时间

image.png 0. 协商缓存(Last-Modified 和 ETag):服务端判断客户端的资源是否发生变化,协商缓存表示资源需要向服务器验证,如果资源没有发生变化,服务器会返回 304 状态码,客户端可以直接从缓存中获取资源。如果不一致,则返回200,重新返回数据。常见的协商缓存策略包括使用 Last-Modified 和 ETag 头字段来控制缓存的验证。其中,Last-Modified 表示资源的最后修改时间,ETag 则是一个资源的标识符(优先使用)。

image.png

总图解:

image.png

刷新操作方式,对缓存的影响
实现方式缓存策略
正常操作地址栏输入 url、跳转链接、前进后退等强制缓存有效,协商缓存有效
手动刷新F5、点击刷新按钮、右击菜单刷新强制缓存失效,协商缓存有效
强制刷新Ctrl + F5强制缓存失效,协商缓存失效