- 一、Javascript
- 1、原始值和引用值类型及区别⭐⭐⭐
- 2、判断数据类型typeof、instanceof、Object.prototype.toString.call()、constructor⭐⭐⭐
- 3、类数组与数组的区别与转换⭐
- 4、undefined和null的区别⭐
- 5、bind、call、apply的区别⭐
- 6、对象的遍历方法有哪些⭐⭐
- 7、原生ajax请求⭐
- 8、JS垃圾回收机制⭐⭐
- 9、JS阻止默认事件以及阻止事件冒泡的方式⭐
- 10、JS继承的实现方式及比较⭐⭐⭐
- 11、了解原型吗?介绍一下原型以及原型链⭐⭐⭐
- 12、了解闭包吗?介绍一下闭包以及闭包的应用场景⭐⭐⭐
- 13、如何正确判断this?⭐⭐⭐
- 14、addEventListener和onClick()的区别⭐
- 15、new和Object.create的区别⭐
- 16、BOM的location对象⭐
- 17、“==”和“===”的区别⭐
- 18、setTimeout用作倒计时为何会产生误差?⭐
- 19、EventLoop(事件循环)⭐⭐⭐
- 20、介绍一下事件委托
- 21、设计模式(单例模式、订阅模式)
- 二、ES6+
- 四、Web存储
- 五、浏览器
- 六、HTTP与计算机网络
- 七、框架(Vue)
- 八、前端工程化
- 九、优化
一、Javascript
1、原始值和引用值类型及区别⭐⭐⭐
js原始值有:undefined、null、number、boolean、string、symbol、bigint,可以通过typeof进行判断
js引用值类型有:Object、Array、Funciton等,可以通过instanceof进行判断
区别:
- js原始值存储在栈中,当把一个变量传递给另一个变量时,是将栈中的值传递给另一个变量,两个变量互不影响,修改一个变量的值不会影响另一个变量的值
js引用值类型会在堆中开辟一块空间存放具体的值,在栈中存储一个变量,这个变量的值是个地址,这个地址指向堆内存中开辟的空间;当将引用值类型传递给其他变量时,传递的是一个内存地址,此时两个变量同时指向同一块内存地址,当其中一个变量修改了地址中的值时,另一个变量中的值也会被修改
2、判断数据类型typeof、instanceof、Object.prototype.toString.call()、constructor⭐⭐⭐
typeof:用于判断基本数据类型,但typeof null的值为Object,所以无法通过typeof判断null、Object、Array的类型,typeof Funtion的值为function这个是特殊情况
instanceof:用于检测构造函数的 prototype 属性是否出现在某个实例对象的原型链上,可用于判断引用值类型
Object.prototype.toString.call():该方法的返回值为”[object 被检测实例的所属类]”,可以判断所有数据类型
constructor:可以获取实例的隐式原型对象上的constructor,检测是否为所属类;不能检测null、undefined因为它们没有constructor属性3、类数组与数组的区别与转换⭐
类数组有:arguments、HTMLCollection(使用querySelectorAll选择的元素集合)、NodeList(node.childNodes)等
区别:相同点:都可用下标来访问每个元素,都有length属性
- 不同点:
- 类数组的类型是Object,数组的类型是Array
- 类数组没有任何Array的属性和方法
实现类数组转换数组
- Array.from(arrayLike)
- Array.prototype.slice.call(arrayLike)
- […arrayLike]
Array.prototype.concat.apply([], arrayLike)
4、undefined和null的区别⭐
相似性:
undefined和null在if语句中会被自动转为false(null和undefined为falsy值)
- undefined == null返回true
不同点:
- null转换为数值时是0,undefined转换为数值时是NaN
- undefined(‘缺少值’):表示此处应该有值,但还未定义
- 变量被声明了,但还未赋值,就为undefined
- 调用函数,应该提供的参数没有提供,该参数就为undefined
- 查找对象没有赋值的属性就为undefined
- 函数没有指定返回值时,默认返回undefined
- null(‘空值’):表示有一个值被定义了,定义为空值
- null作为对象原型链的终点
- 对象赋值为null,表示该对象为空值
- 三者都可以改变函数的this指向
- 三者第一个参数都是this要指向的对象,如果没有这个参数或参数为undefined或null,则默认指向全局window
- 三者都可以利用后续参数传参
不同点:
- call可以传入多个参数,apply需要传入一个参数数组,而bind可以一次性传入参数也可以分多次传入
call、apply是立即执行,bind不会立即执行,而是返回一个修改this后的函数
6、对象的遍历方法有哪些⭐⭐
for…in
- Objcet.keys():返回包含key的数组
- Object.values():返回包含value的数组
- Object.entries():返回包含(key,value)的数组
- Object.getOwnPropertyNames():返回包含自身key的数组
上述方法都无法遍历对象中的Symbol类型的属性,以下是可以遍历Symbol的方法
- Object.getOwnPropertySymbols():返回对象中只包含symbol类型key的数组
- Reflect.ownKeys():返回对象中所有类型key的数组(包含symbol类型)
7、原生ajax请求⭐
ajax是一种异步请求的方式,客户端给服务器发送请求,从服务器获取数据,从而达到局部刷新页面的效果
过程:
- 创建XMLHttpRequest请求
- 调用open方法设置请求方式和url
- 使用send方法给服务器发送数据,开始请求
- 注册onreadystatechange事件,通过readystate和status判断是否正确响应
8、JS垃圾回收机制⭐⭐
机制:找出那些不再继续使用的值,然后释放其占用的内存。垃圾回收机制会每隔一段时间就执行一次释放操作
策略:
- 标记清除:
-
9、JS阻止默认事件以及阻止事件冒泡的方式⭐
event.stopPropagation():可以阻止事件冒泡,但不会阻止默认行为
- event.preventDefault():可以阻止事件默认行为,但不会阻止事件冒泡
return false:即阻止了事件冒泡,又阻止了事件默认行为
10、JS继承的实现方式及比较⭐⭐⭐
11、了解原型吗?介绍一下原型以及原型链⭐⭐⭐
原型:每个JavaScript对象都有一个私有属性proto,该属性指向它的构造函数的原型对象(prototype),该对象包含了构造函数共享的所有属性和方法,每个实例对象都会继承这些属性和方法。
原型链:当访问一个对象的属性时,如果对象本身不存在该属性,那么就会去它的原型对象上找,而原型对象也会有自己的原型,就这样一层层往上找,直到找到该属性或者达到原型链的末端(null)为止,这就是原型链的概念12、了解闭包吗?介绍一下闭包以及闭包的应用场景⭐⭐⭐
介绍一下闭包
闭包指的是有权访问另一个函数作用域中变量的函数。创建闭包最常见的方式就是在一个函数内部创建一个新的函数,并且将这个新函数返回出去;内部函数可以使用外部函数的局部变量,并且当外部函数的函数执行上下文被销毁时,返回出来的内部函数依然可以使用外部函数的局部变量,这是因为内部函数引用了外部函数的变量对象,使其保留在内存当中不会被回收;当闭包过多时,会造成内存泄漏
闭包的应用场景模拟块级作用域
- 模拟私有变量
- 创建模块
-
13、如何正确判断this?⭐⭐⭐
this是在函数运行时确定的,有四种执行函数的方式
默认调用,
fn()
直接调用。函数的this指向的是全局变量,在浏览器环境下指向window,在node环境下为undefined- 隐式绑定,
obj.fn()
。函数的this指向的是调用函数的对象 - 显示绑定,通过call、apply、bind绑定的函数,函数的this会指向绑定后的this
new调用,使用new运算符时,函数会将this指向新创建的对象,并执行其构造函数为对象添加属性和方法
14、addEventListener和onClick()的区别⭐
addEventListener 可以对同一个元素绑定多个事件,执行顺序从上到下依次执行;而 onclick 同一个元素只能绑定一个事件,如有多个,后面的事件会覆盖前面的事件
- addEventListener 可以通过第三个参数来控制触发阶段,默认为false,也就是执行的冒泡机制,如为true,则执行捕获机制
- addEventListener 它对任何 DOM 元素都是有效的,而不仅仅只对 HTML 元素有效
- 注册 addEventListener 事件时不需要写 on ,而 onclick 方式则必须加 on
- 在移除事件上,onclick 使用的是指针指向 null ,例如 document.onclick = null ,而 addEventListener 注册的事件可以通过 removeEventListener 方法移除(要使用此方法,addEventListener必须执行的是外部函数或存在函数名,不然则不能使用)
- addEventListener 为 DOM2 级事件绑定,onclick 为 DOM0 级事件绑定
在IE 9之前,必须使用 attachEvent 而不是使用 addEventListener
15、new和Object.create的区别⭐
new 操作符创建的实例能继承构造函数上的属性和方法以及原型上的属性和方法;而 Object.create 创建的实例只继承了原型上的属性和方法,没有继承构造函数上的属性和方法
16、BOM的location对象⭐
17、“==”和“===”的区别⭐
使用“==”进行比较时会先进行隐式类型转换,再进行比较;而“===”则不会进行类型转换,只有当类型和值都相同的情况下才为 true
- undefined == null -> true,而 undefined === null -> false
18、setTimeout用作倒计时为何会产生误差?⭐
定时器属于宏任务,当js线程中执行时间大于定时器时间时,定时器的回调会放到宏任务队列中,来不及调用,所以这个时间会产生误差
可以举一个例子:有一个五秒的定时器,五秒后打印’123’;当执行定时器时,定时器会放到定时器线程中计时,继续执行主线程当中的任务,当定时器计时结束后,会放到宏任务队列当中;而主线程执行完毕后,会取出微任务队列中的任务执行,必须保证微任务队列中的任务全部执行完毕时,才会去宏任务队列取出下一个任务执行;若主线程或微任务中有耗时的事件,执行时间大于定时器的时间时,这时就会导致定时器任务延迟执行,产生误差19、EventLoop(事件循环)⭐⭐⭐
JavaScript是单线程的,为了防止代码执行时间过长阻塞后续代码的执行,JavaScript将所有执行任务分为了同步任务和异步任务,JavaScript会先将同步任务压入执行栈,依次执行;将异步任务放到任务队列中,任务队列又分为宏任务队列和微任务队列,宏任务包括:定时器、ajax请求、DOM事件等,微任务包括:promise.then、async/await、MutationObserver、queueMicrotask等,在执行下一个宏任务之前要保证微任务队列清空
事件循环:首先将 script 中的代码压入执行栈,依次执行;执行过程中产生的异步任务放到任务队列当中,当主线程的同步任务执行完毕后,按入队顺序依次执行微任务队列中的任务,直到微任务队列清空为止;当微任务队列清空后,一次循环结束,取出下一个宏任务执行,按照这种方式循环往复,直到所有任务执行完毕,这种机制称为事件循环机制20、介绍一下事件委托
事件冒泡:当事件源触发事件时,事件会沿着包含关系,依次向上层传递,每一层都可以感知事件,直到传递到根元素,这个过程称为事件冒泡
事件委托:本质上是利用了事件冒泡的机制,因为事件在冒泡的过程中会传递到父节点,并且父节点可以通过事件对象获取目标节点,因此可以把子元素的事件监听函数定义在父节点上,由父节点的监听函数统一处理多个子元素的事件(减少内存消耗),这种方式称为事件委托21、设计模式(单例模式、订阅模式)
二、ES6+
1、symbol是什么?怎么判断symbol?symbol使用场景有哪些?⭐⭐
- symbol是什么?
- symbol是一种基本数据类型,它可以由Symbol()函数或Symbol.for()函数创建
- Symbol()函数每次都会返回新的symbol值,且都是唯一的,不支持new语法
- Symbol.for()函数返回一个全局的symbol值,Symbol.for()不会每次都返回新的symbol值,会先检查全局中是否存在相同key值的symbol,存在则返回相同的symbol,不存在再创建新symbol
- 怎么判断symbol?
- typeof
- Object.prototype.toString.call()
- symbol的使用场景有哪些?
- 用于对象的属性名,保证不会出现同名的属性
- 对象由多模块构成,防止某一个键不小心被改写或覆盖
- 可用于定义一组常量(枚举),保证常量的值都是不相等的,常用于switch判断中
- 为对象定义一些非私有、但又希望只用于内部的方法
- 由于以 Symbol 值作为键名,不会被常规方法遍历得到。我们可以利用这个特性,为对象定义一些非私有的、但又希望只用于内部的方法
- 注意:symbol并不能实现真正的私有变量的效果,只是不能通过常规的遍历方法拿到symbol类型的属性而已
- 消除代码中多次出现的字符串或数值(魔术字符串),可保持良好风格的代码,减少代码耦合
```javascript
//高耦合 修改的时候很麻烦 不利于后期维护
switch(xxx){
case ‘test1’ … } foo(‘test1’)
// 由变量代替,修改时只需要修改变量的值,若对属性值没有要求,则可以使用Symbol()保持变量值唯一 const type = { test1: Symbol() } switch(xxx){ case type.test1 … } foo(type.test1)
- 模块的singleton模式,即调用一个类,任何时候返回的都是同一个实例
<a name="TtNTT"></a>
## 2、let、const和var的区别⭐⭐⭐
- var在全局作用域声明变量会挂载到window对象上,而const、let不会
- var在预编译阶段会进行变量提升,而const、let不会
- const、let有块级作用域,var没有
- const、let有暂时性死区,在变量被定义之前不能访问
- const、let不能重复声明变量,var可以
- const代表常量,在声明变量时必须有初始化值否则会报错
- const声明对象不能修改指针,但是可以修改属性值
<a name="h4ZHv"></a>
## 3、箭头函数与普通函数的区别⭐⭐⭐
- 声明方式不同
- 普通函数可以是具名函数,也可以是匿名函数
- 箭头函数只能创建匿名函数,不过可以通过表达式的方式具名
- this指向不同
- 普通函数的this指向函数运行时说所在的对象
- 箭头函数没有自己的this,它的this指向定义时上层作用域的this
- 箭头函数的this不能通过call、apply、bind改变
- 箭头函数没有原型prototype
- 箭头函数没有自己的arguments
- 如果箭头函数是在全局作用域下执行,那么获取arguments会报错
- 如果处于普通函数作用域中,那么arguments则是上层普通函数的arguments
- 可以使用rest剩余参数代替
- 箭头函数不能作为构造函数
- 不能使用new关键字
- 没有new.target
- 箭头函数不能重复函数参数名称
- 箭头函数不可以使用yield命令,不能作为generator函数
<a name="AaPSg"></a>
## 4、async 会取代 Promise 吗?⭐
1. async函数返回一个Promise对象
2. 面对复杂的异步流程,Promise提供的all、race会更好用
3. Promise本身是一个对象,所以可以在代码中任意传递
4. async的支持率还很低,即使有babel,编译后也要增加1000多行代码
<a name="q4u9Y"></a>
## 5、ES Module执行原理⭐
![image.png](https://cdn.nlark.com/yuque/0/2022/png/26749762/1664966750208-4957c8d3-d78e-4eff-901e-07d4d50198a4.png#averageHue=%23fbfbfb&clientId=ua542dbf0-d616-4&crop=0&crop=0&crop=1&crop=1&from=paste&id=uf4728d3d&margin=%5Bobject%20Object%5D&name=image.png&originHeight=595&originWidth=1563&originalType=url&ratio=1&rotation=0&showTitle=false&size=315085&status=done&style=none&taskId=u9fa19d82-5e37-4bd0-83f9-a6c84c9a6db&title=)<br />ES Module分为三个阶段:构造阶段、实例化阶段、求值阶段
- 构造阶段:
- 根据入口创建依赖关系的AST
- 下载module文件,用于解析
- 解析每个module文件,生成 Module Record(包含当前module的AST、变量等)
- 将Module Record 映射到 Module Map(URL-Module Record)中,保持每个module文件的唯一性
- 实例化阶段(动态绑定):
- 生成每个Module Record的块环境记录(Module Enviroment Record),用来管理 Module Record 的变量等
- 在内存中开辟空间存放每个Module的导出的内容,同时 Module文件export和 import都指向该地址(此时内存中存放的数据还未赋值)
- 求值阶段:
- JS 引擎通过执行顶层代码(函数之外的代码,此处可以理解为模块文件中顶层作用域中的代码)来给内存区的引用赋值
<a name="mHnND"></a>
## 6、介绍一下Promise以及Promise A+⭐⭐
<a name="dzh6W"></a>
## 7、setTimeout、Promise、async/await的区别⭐⭐
<a name="Xr8L7"></a>
## 8、Promise的缺点
- 无法取消 Promise,一旦创建它就会立即执行,无法中途取消
- 如果不设置回调或者 catch ,Promise 内部抛出的错误,无法反应到外部,不会影响外部代码的执行
- 当处于 pending 状态的时候,无法得知目前进展到哪一个阶段(刚刚开始还是即将完成)
<a name="VaqQE"></a>
# 三、HTML、CSS
<a name="KsHUA"></a>
## 1、link和@import的区别⭐
1. link属于html标签,而@import是css提供
2. 页面被加载时,link会同时被加载,而@import引用的css会等到页面被加载完再加载
3. 兼容性问题:@import只在IE5以上才能识别,而link是html标签,无兼容性问题
4. 权重问题:@import的权重要高于link
5. DOM操作:DOM可以操作link中的样式,而不可以操作@import中的样式
<a name="WrKdQ"></a>
## 2、script标签中defer和async区别⭐⭐
![](https://cdn.nlark.com/yuque/0/2022/webp/26749762/1662105219366-1e4a7cbf-4afe-4a30-8429-a518d21238a4.webp#averageHue=%23f9f8f7&clientId=uab3c0d28-bfcf-4&crop=0&crop=0&crop=1&crop=1&from=paste&id=u1184ddf7&margin=%5Bobject%20Object%5D&originHeight=568&originWidth=1017&originalType=url&ratio=1&rotation=0&showTitle=false&status=done&style=none&taskId=uf885b530-0f77-43a8-9b77-bc37c9a8c6c&title=)
<a name="whTAy"></a>
## 3、介绍一下盒子模型⭐⭐⭐
- 网页中所有元素都可以看做一个盒子,由content + padding + margin + border组成
- 盒子模型有两种,可以通过box-sizing切换
- 标准盒模型(content-box):width = content + border + padding + margin
- IE盒模型(border-box):width = (content + border + padding) + margin
<a name="KgBSI"></a>
## 4、块级元素、行内元素、替换元素、非替换元素⭐
**块级元素(display:block)**
- 特点
- 默认独占一行,且在其左右两边没有其它元素
- 可以设置宽高,不设置宽度的情况下,默认与父元素宽度一致
- 常见元素:div、h1、h2、p、ul
**行内元素(display:inline)**
- 特点
- 左右两边都可以有其它元素,和其它元素在一行上
- 不可以设置宽高,其宽度就是内容的宽度
- margin仅对左右方向有效,上下无效
- padding上下左右都有效,padding上下对其它元素无影响
- 常见元素:span、a、img
**替换元素:浏览器根据元素的标签和属性,来决定元素的具体显示内容**
- 常见元素:img(src属性)、input(type属性)、textarea等
**非替换属性:元素内容直接显示**
- 常见元素:div、p等大部分元素
<a name="u7hpu"></a>
## 5、img标签的title和alt区别⭐
title:当图片名字、路径都正确时,当鼠标移到图片的区域范围内,会显示出title的信息<br />alt:当图片名字不正确或者当图片的路径有错误时,在本来显示图片的位置里显示出alt的内容,以方便自己或者用户识别该图片是干什么的
<a name="X0qGr"></a>
## 6、CSS选择器有哪些?⭐
id选择器(#myid)、类选择器(.myclassname)、标签选择器(div, h1, p)、相邻选择器(h1 + p)、子选择器(ul > li)、后代选择器(li a)、通配符选择器(*)、属性选择器(a[rel="external"])、伪类选择器(a:hover, li:nth-child)
<a name="GXVxO"></a>
## 7、CSS哪些样式属性可以继承?⭐⭐
继承的概念:指的是子节点默认使用父节点的样式属性<br />可继承的属性:颜色 文字 字体间距 行高 对齐方式 列表的样式
:::tips
内联元素可继承:letter-spacing、word-spacing、white-space、line-height、**color**、**font**、**font-family**、**font-size**、font-style、font-variant、font-weight、text-decoration、text-transform、direction<br />终端块状元素可继承:text-indent、**text-align**<br />列表元素可继承:list-style、list-style-type、list-style-position、list-style-image
:::
<a name="ULoDH"></a>
## 8、水平垂直居中的方法⭐⭐⭐
定宽高
:::tips
1. 绝对定位 + margin负值
2. 绝对定位 + transform
- transform:translate(-50%,-50%)
3. 绝对定位 +(left/right/top/bottom):0 + margin:auto
4. flex布局
5. gird + margin:auto
6. 父(table-cell + vertical-align + text-align)+ 子( inline-block/margin:auto)
:::
不定宽高
:::tips
1. 绝对定位 + transform
2. flex布局
3. 父(table-cell + vertical-align + text-align) + 子(inline-block)
4. gird + margin:auto
5. gird + flex
:::
<a name="o3FTK"></a>
## 9、清除浮动的方法⭐⭐
1. clear清除浮动(添加空div法)在浮动元素下方添加空div,并给该元素写css样式
> {clear:both;height:0;overflow:hidden;}
2. 父级添加overflow:hidden(BFC)
3. 父级设置为inline-block
4. 万能清除法,after伪类
> float_div:after{ content:"."; clear:both; display:block; height:0; overflow:hidden; visibility:hidden; } .float_div{ zoom:1 }
<a name="Jv6a6"></a>
## 10、visibility: hidden、display: none、opacity:0区别⭐⭐
- display:none,元素会隐藏且不会占用文档流,会导致页面的**重绘**和**重排**,不能触发点击事件
- visibility:hidden,元素会隐藏但会占用文档流,只会导致页面**重绘**,不能触发点击事件,具有继承性
- opacity:0,元素会隐藏(透明度变为0)会占用文档流,不会导致重排**,不一定**会产生重绘,可以触发点击事件
:::tips
元素提升为合成层后,transform 和 opacity 不会触发 repaint,如果不是合成层,则其依然会触发 repaint<br />在 Blink 和 WebKit 内核的浏览器中,对于应用了 transition 或者 animation 的 opacity 元素,浏览器会将渲染层提升为合成层,也可以使用 translateZ(0) 或者 translate3d(0,0,0) 来人为地强制性地创建一个合成层
:::
<a name="yG5K1"></a>
## 11、如何理解HTML语义化⭐⭐⭐
1. 增加代码可读性,让人更容易读懂
2. 有利于SEO,有助于爬虫抓取更多有效的信息:爬虫依赖于标签来确定上下文和各个关键字的权重
3. 在没有CSS样式的情况下,页面也能呈现出很好地内容结构、代码结构
4. 方便其它设备解析(如屏幕阅读器、盲人阅读器、移动设备),以有意义的方式来渲染页面
<a name="HWGJP"></a>
## 12、CSS优先级⭐⭐
CSS优先级一般是`!import > 内联> id > class > 标签选择器`<br />涉及多选择器判断优先级时就需要用到优先级算法
> 优先级是由 A 、B、C、D 的值来决定的,其中它们的值计算规则如下:
> - 如果存在内联样式,那么 A = 1,否则 A = 0
> - B 的值等于 ID选择器(#id) 出现的次数
> - C 的值等于 类选择器(.class) 和 属性选择器(a[href="https://example.org"]) 和 伪类(:first-child) 出现的总次数
> - D 的值等于 标签选择器(h1,a,div) 和 伪元素(::before,::after) 出现的总次数
>
从左到右比较,如果样式优先级相等,取后面出现的样式
<a name="PCdPC"></a>
## 13、回流、重绘的理解⭐⭐
回流(重排):当DOM的变化影响了元素的几何信息,浏览器需要重新计算元素的几何属性,将其安放在界面中的正确位置,这个过程叫做重排。表现为重新生成布局,重新排列元素<br />重绘:当一个元素的外观发生改变,但没有改变布局,重新把元素外观绘制出来的过程,叫做重绘。表现为某些元素的外观被改变
<a name="uFJBl"></a>
## 14、何时触发回流、重绘?⭐
**回流**这一阶段主要是计算节点的位置和几何信息,当页面布局和几何信息发生变化的时候就会触发**回流**
- 添加或删除可见DOM元素
- 元素的位置发生变化
- 元素的尺寸发生变化(包括外边距、内边框、边框大小、高度和宽度等)
- 内容发生变化,比如文本变化或图片被另一个不同尺寸的图片所替代
- 页面一开始渲染的时候(这肯定避免不了)
- 浏览器的窗口尺寸变化(因为回流是根据视口的大小来计算元素的位置和大小的)
**重绘**是一个元素外观的改变所触发的浏览器行为
- **触发回流一定会触发重绘**
- 改变元素的外观如:颜色、背景颜色、outline等
<a name="vR3f4"></a>
## 15、如何减少回流、重绘?⭐⭐
- **减少重绘和重排**,比如样式集中改变,使用添加新样式类名`.class` 或`cssText`
- **批量修改DOM**,DOM元素离线修改(隐藏元素 -> 应用修改 -> 重新显示),使用文档片段`document.createDocumentFragment()`处理完之后再拷贝回文档
- 使元素脱离文档流
- 对其进行多次修改
- 将元素带回文档中
- **避免触发同步布局事件**,如获取offsetWidth等属性,因为它会强制浏览器刷新队列,可以将其保存到临时变量进行缓存
- **使用** **absolute 或 fixed 使元素脱离文档流**,这在制作复杂的动画时对性能的影响比较明显
- **开启 GPU 加速**,利用 transform、opacity、filters、will-change 这些属性处理动画,不会引起回流重绘 (会提高内存占用)
<a name="sdkoM"></a>
## 16、CSS sprites是什么?有什么优缺点?⭐
CSS sprites又称精灵图,是一种网页图片应用处理方式,就是将网页中一些背景图片整合到一张图片中<br />使用方法:<br />当需要特定图像(精灵图)时,一般会通过CSS background-images 属性引用精灵表,在通过CSS background-position 属性对其进行偏移定位得到所需的精灵图,然后以像素为单位定义精灵图的大小。<br />优点:
- 减少网页的http请求,提高页面的加载速度
- 增加图片信息重复度,提高压缩比,减少图片总大小
- 减少了命名困扰:只需对一张集合的图片命名,不需要对每一个小元素进行命名,提高制作效率
- 更换风格方便:只需在一张或几张图片上修改颜色或样式即可实现
缺点:
- 图片合并麻烦
- 背景设置时,需要得到每一个背景单元的精确位置
- 维护麻烦,修改啊一个图片可能需要重新布局整个图片,样式
<a name="m5ZAB"></a>
## 17、CSS超出一行或多行显示省略号⭐
单行
```css
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
多行
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 2;/* 表示行数,设置超出多少行后显示 */
-webkit-box-orient: vertical;
18、什么是BFC?怎么创建BFC?BFC有哪些应用场景?⭐⭐
BFC是块格式化上下文,是 Web 页面的可视 CSS 渲染的一部分,是块级盒子的布局过程发生的区域,也是浮动元素与其他元素交互的区域
创建BFC的方式:
- 根元素()
- 浮动元素(float 值不为 none)
- 绝对定位元素(position 值为 absolute 或 fixed)
- 行内块元素(display 值为 inline-block)
- 表格的标题和单元格(display 为 table-caption,table-cell)
- 匿名表格单元格元素(display 为 table 或 inline-table)
- overflow 值不为 visible、clip 的块元素
- 弹性元素(display 值为 flex 或 inline-flex 元素的直接子元素)
- 网格元素(display 值为 grid 或 inline-grid 元素的直接子元素)
BFC的特性:
- BFC 会创建一个隔离的空间
- BFC 内部的块级盒会在垂直方向上一个接一个排列
- 同一个 BFC 下的相邻块级元素可能发生外边距折叠,创建新的 BFC 可以避免的外边距折叠
- 每个元素的外边距盒(margin box)的左边与包含块边框盒(border box)的左边相接触(从右向左的格式化,则相反),即使存在浮动也是如此
- 浮动盒的区域不会和 BFC 重叠
- 计算 BFC 的高度时,浮动元素也会参与计算
BFC的应用
- 自适应多栏布局
- 左右两边固定浮动,中间栏创建BFC
- 防止外边距重叠
- 解决浮动元素高度塌陷的问题(清除浮动)
19、两栏布局(左侧固定+右侧自适应)⭐⭐
<div class="outer">
<div class="left">左侧</div>
<div class="right">右侧</div>
</div>
左侧元素左浮动设置固定宽度,右侧元素
margin-left
值设置为左侧固定宽度.outer {
height: 100px;
}
.left {
float: left;
width: 200px;
height: 100%;
background: lightcoral;
}
.right {
margin-left: 200px;
height: 100%;
background: lightseagreen;
}
左侧元素左浮动设置固定宽度,右侧元素设置
overflow:hidden
创建BFC.outer {
height: 100px;
}
.left {
float: left;
width: 200px;
height: 100%;
background: lightcoral;
}
.right {
overflow: hidden;
height: 100%;
background: lightseagreen;
}
利用
flex
布局,左侧元素固定宽度,右侧元素设置flex:1
.outer {
display: flex;
height: 100px;
}
.left {
width: 200px;
height: 100%;
background: lightcoral;
}
.right {
flex: 1;
height: 100%;
background: lightseagreen;
}
父元素设置相对定位,左侧元素设置
position:absolute
绝对定位,宽度固定,右侧元素设置margin-left
为左侧固定宽度.outer {
position: relative;
height: 100px;
}
.left {
position: absolute;
left: 0;
width: 200px;
height: 100%;
background: lightcoral;
}
.right {
margin-left: 200px;
height: 100%;
background: lightseagreen;
}
父元素设置相对定位,左侧元素设置固定宽度,右侧元素设置
position:absolute
绝对定位,left
为宽度大小,其余方向定位为0.outer {
position: relative;
height: 100px;
}
.left {
width: 200px;
height: 100%;
background: lightcoral;
}
.right {
position: absolute;
left: 200px;
top: 0;
right: 0;
bottom: 0;
background: lightseagreen;
}
20、三栏布局(左右固定,中间自适应)⭐⭐⭐
HTML结构
<div class="container">
<div class="left">左边</div>
<div class="right">右边</div>
<div class="main">中间</div>
</div>
浮动 + margin
.left, .right, .main {
height: 100px;
}
.left {
float: left;
width: 200px;
background-color: red;
}
.right {
float: right;
width: 200px;
background-color: blue;
}
.main {
margin: 0 200px;
background-color: green;
}
浮动 + BFC
.left, .right, .main {
height: 100px;
}
.left {
float: left;
width: 200px;
background-color: red;
}
.right {
float: right;
width: 200px;
background-color: blue;
}
.main {
overflow: hidden;
background-color: green;
}
定位 + margin
.left, .right, .main {
height: 100px;
}
.container {
position: relative;
}
.left {
position: absolute;
left: 0;
width: 200px;
background-color: red;
}
.right {
position: absolute;
right: 0;
width: 200px;
background-color: blue;
}
.main {
margin: 0 200px;
background-color: green;
}
HTML结构
<div class="container">
<div class="left">左边</div>
<div class="main">中间</div>
<div class="right">右边</div>
</div>
flex布局
.container {
display: flex;
height: 100px;
}
.left {
width: 200px;
background-color: red;
}
.main {
flex: 1;
background-color: green;
}
.right {
width: 200px;
background-color: blue;
}
table布局
.container {
display: table;
height: 100px;
width: 100%;
}
.left {
width: 200px;
display: table-cell;
background-color: red;
}
.main {
display: table-cell;
background-color: green;
}
.right {
width: 200px;
display: table-cell;
background-color: blue;
}
圣杯布局
- 双飞翼布局
21、圣杯布局、双飞翼布局(经典三栏布局)⭐⭐
经典三栏布局
- 中间一栏最先加载和渲染
- 两侧内容固定,中间内容自适应
圣杯布局
<div class="container">
<div class="main">中间</div>
<div class="left">左边</div>
<div class="right">右边</div>
</div>
.left, .right, .main {
height: 100px;
}
.container {
margin-left: 200px;
margin-right: 200px;
}
.main {
float: left;
width: 100%;
background-color: green;
}
.left {
float: left;
position: relative;
left: -200px;
margin-left: -100%;
width: 200px;
background-color: red;
}
.right {
float: left;
position: relative;
right: -200px;
margin-left: -200px;
width: 200px;
background-color: blue;
}
双飞翼布局
<div class="content">
<div class="main">中间</div>
</div>
<div class="left">左边</div>
<div class="right">右边</div>
.left, .right, .main {
height: 100px;
}
.content {
float: left;
width: 100%;
}
.main {
margin-left: 200px;
margin-right: 200px;
background-color: green;
}
.left {
float: left;
margin-left: -100%;
width: 200px;
background-color: red;
}
.right {
float: left;
margin-left: -200px;
width: 200px;
background-color: blue;
}
22、CSS3多媒体类型
23、介绍一下flex布局⭐⭐
flex布局是CSS3新增的一种布局方式,可以通过将一个元素的display属性值设置为flex从而使它成为一个flex容器,它的所有子元素都会成为它的项目。一个容器默认有两条轴:一个是水平的主轴,一个是与主轴垂直的交叉轴。可以使用flex-direction来指定主轴的方向。可以使用justify-content来指定元素在主轴上的排列方式,使用align-items来指定元素在交叉轴上的排列方式。还可以使用flex-wrap来规定当一行排列不下时的换行方式。对于容器中的项目,可以使用flex-basis设置项目本身的大小,还可以使用order属性来指定项目的排列顺序,还可以使用flex-grow来指定当排列空间有剩余的时候,项目的放大比例,还可以使用flex-shrink来指定当排列空间不足时,项目的缩小比例
24、移动端响应式适配方案⭐⭐
- 媒体查询:使用@media媒体查询可以针对不同的媒体类型定义不同的样式,特别是响应式页面,可以针对不同屏幕的大小,编写多套样式,从而达到自适应的效果
- 优点:
- 实现简单,只需要编写css代码
- 调整屏幕宽度时不需要刷新页面就可以实现响应式布局
- 缺点:
- 代码量大,不方便维护
- 不能够完全适配所有的尺寸,需要编写多套css样式
- 百分比布局方案
- rem+媒体查询
rem方案:基于rem,使用 js 动态设置根字体
function adapter(){
//获取布局视口宽度
const dpWidth = document.documentElement.clientWidth
//计算根字体大小
const rootFonstSize = (dpWidth * 100)/375
//设置根字体大小
document.documentElement.style.fontSize = rootFonstSize + 'px'
}
adapter()
window.onresize = adapter
viewport方案:vw/vh
vw:viewport’s width的缩写,1vw表示 window.innerWidth 的1% vh:viewport’s height的缩写,1vh表示 window.innerHeight 的1% vmin:vw和vh之间最小值 vmax:vw和vh之间最大值
实现步骤:
- 设置meta标签,让当前的viewport的宽度等于设备的宽度,并且不允许用户手动缩放
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0">
安装 postcss-px-to-viewport 插件(配置好后,可自动将 px 转换成 vw ),进行相应地配置,在项目中直接使用px即可
25、CSS中各种百分比⭐
width/height
- 百分比计算基于包裹它的父元素的宽度和高度计算
- 特殊情况:父元素没有明确定义盒子高度(未设定 height 或使用 min/max-height 时),这时使用百分比等同于 auto
- margin/padding
- 百分比计算基于其父元素的宽度计算
- border-radius
- 横轴上的百分比参考的是元素自身的宽度,纵轴上的百分比参考的是元素自身的高度,负值是无效的
- background-position:背景图片在背景中的位置
- 百分比计算:
(父元素-背景图片)* 百分比
计算得出背景的位置(左上角)
- 百分比计算:
- font-size
- 百分比计算基于父元素的 font-size
- vertical-align:纵向对齐
- 百分比基于自身的 line-height
- left/right/top/bottom
- top/bottom 基于父元素的高度,left/right基于父元素的宽度
transform:translate()
- 百分比基于自身的宽度和高度
26、viewport的基本概念⭐
通常viewport是指视窗、视口,浏览器上(也可能是一个app中的webview)用来显示网页的那部分区域。在移动端和pc端视口是不同的,pc端的视口是浏览器窗口区域,而在移动端有三个不同的视口概念:布局视口、视觉视口、理想视口
布局视口:指网页的宽度,一般移动端浏览器都默认设置了布局视口的宽度。根据设备的不同,布局视口的默认宽度有可能是768px、980px或1024px等,这个宽度并不适合在手机屏幕中展示。移动端浏览器之所以采用这样的默认设置,是为了解决早期的PC端页面在手机上显示的问题;过大的宽度会导致浏览器出现横向滚动条的情况
视觉视口:用户通过屏幕看到的页面区域,通过缩放查看显示内容的区域,在移动端缩放不会改变布局视口的宽度,当缩小的时候,屏幕覆盖的css像素变多,视觉视口变大,当放大的时候,屏幕覆盖的css像素变少,视觉视口变小
理想视口:指对设备来讲最理想的视口尺寸。采用理想视口的方式,可以使网页在移动端浏览器上获得最理想的浏览和阅读的宽度
在开发中,为了实现理想视口,需要给移动端页面添加标签配置视口<meta name="viewport" content="width=device-width">
,通知浏览器来进行处理27、伪类和伪元素的区别
伪类:它用于选择处于特定状态的元素,比如当它们是这一类型的第一个元素时,或者是当鼠标指针悬浮在元素上面的时候,并为其应用相应的样式
伪元素:伪元素为DOM树没有定义的虚拟元素。不同于其他选择器,它不以元素为最小选择单元,它选择的是元素指定内容。比如 ::before 表示选择元素内容的之前内容,也就是 “” ; ::selection 表示选择元素被选中的内容
区别:
- 百分比基于自身的宽度和高度
伪类操作对象是文档树中已有的元素,而伪元素则是创建了一个文档树以外的元素(假元素,存在于浏览器当中)
伪类使用的是单冒号,CSS3规定伪元素使用的是双冒号(为了兼容性,也可采用单引号)
28、meta标签
定义:
meta 标签可以提供有关页面的元信息,比如针对搜索引擎和更新频度的描述和关键词
- meta 标签位于文档的头部,不包含任何内容
- meta 标签的属性定义了与文档相关联的名称/值对
属性:
用法:
实例1:定义文档关键词,用于搜索引擎
<meta name="keywords" content="HTML, CSS, XML, XHTML, JavaScript">
实例2:定义web页面描述
<meta name="description" content="hello world">
实例3:定义页面作者
<meta name="author" content="me">
实例4:每30秒刷新页面
<meta http-equiv="refresh" content="30">
四、Web存储
1、localStorage、sessionStorage、cookie的区别⭐⭐⭐
相同点:
- 它们都是浏览器存储数据的方式
- 它们都受到同源策略的限制
不同点:
- 从存储大小来说
- cookie存储大小为4kb,而localstorage、sessionstorage存储大小为5MB
- 从生命周期来说
- cookie没有设置过期时间的话,默认是会话cookie,当关闭tab或浏览器时,数据就会被清空;当设置了过期时间的话,cookie会被保存在硬盘中,等到了过期时间才会被清空
- localstorage是本地存储,是一种持久化的存储方式,如果不手动清除的话,它就会一直保存在硬盘中
- sessionstorage是会话存储,当关闭tab或浏览器时,数据就会被清空
从能否与服务器进行交互来说
优点:
- 数据存于浏览器缓存中,可以同域名下,跨tab界面数据交互
- 存储时间长,关闭浏览器也不会被清除掉
- 存储大小可达5M
- 缺点:
- 任何数据存储后,都会被转化为字符串
- 手动清除浏览器缓存后就会被销毁
- 适合存储简单型数据,单、多页面应用均可以使用
闭包缓存的优缺点
- 优点:
- 可以存储JavaScript的任何形态数据,且不会被转化
- 手动清除浏览器缓存也不影响
- 缺点:
- 无法跨tab界面数据交互
- 存储时间短,关闭tab页后就会被销毁
- 存在JavaScript内存中,缓存过多的数据可能会影响性能,严重会导致内存溢出
-
3、Vuex与localStorage存储的区别⭐
从存储位置来说
- localStorage存储在硬盘中,Vuex数据存储在内存中
- 从存储空间来看
- Vuex取决于可用内存和浏览器的限制
- localStorage一般默认大小为5MB
- 从生命周期来说
- localStorage是本地存储,数据是持久化的,如果不手动清除则数据不会消失
- Vuex与页面的生命周期相同,如关闭页面,刷新页面都会使数据消失
- 从页面共享来看
- Vuex无法跨标签页或页面共享数据,localStorage可以在同源页面下共享
- 从用途来说
- Vuex是用于管理页面以及组件的状态,而localStorage主要用于存储数据
从是否能响应式来说
不能读取和修改对方DOM
- 不能访问对方的Cookie、IndexDB和LocalStorage
- 限制XMLHttpRequest请求
但有三个标签允许跨域加载资源:img、link、script
为什么ajax请求跨域时,拿不到响应信息?
跨域是为了阻止用户读取到另一个域名下的内容,Ajax 可以获取响应,浏览器认为这不安全,所以拦截了响应
2、浏览器的渲染过程⭐⭐⭐
- 解析HTML,生成DOM树,解析CSS,生成CSSOM树
- 将DOM树和CSSOM树结合,生成渲染树(Render Tree)
- Layout(回流):根据生成的渲染树,进行回流(Layout),得到节点的几何信息(位置,大小)
- Painting(重绘):根据渲染树以及回流得到的几何信息,得到节点的绝对像素
- Display:将像素发送给GPU,展示在页面上。
3、介绍XSS攻击以及预防方案⭐⭐⭐
什么是XSS攻击?
Cross-Site Scripting(跨站脚本攻击)简称 XSS,是一种代码注入攻击。攻击者通过在目标网站上注入恶意脚本,使之在用户的浏览器上运行。利用这些恶意脚本,攻击者可获取用户的敏感信息如 Cookie、SessionID 等,进而危害数据安全
XSS 的本质是:恶意代码未经过滤,与网站正常的代码混在一起;浏览器无法分辨哪些脚本是可信的,导致恶意脚本被执行
XSS有哪些注入的方法?
- 在 HTML 中内嵌的文本中,恶意内容以 script 标签形成注入
- 在内联的 JavaScript 中,拼接的数据突破了原本的限制(字符串,变量,方法名等)
- 在标签属性中,恶意内容包含引号,从而突破属性值的限制,注入其他属性或者标签
- 在标签的 href、src 等属性中,包含 javascript: 等可执行代码
- 在 onload、onerror、onclick 等事件中,注入不受控制代码
- 在 style 属性和标签中,包含类似
background-image:url("javascript:...");
的代码(新版本浏览器已经可以防范) - 在 style 属性和标签中,包含类似
expression(...)
的 CSS 表达式代码(新版本浏览器已经可以防范)
XSS能做哪些事情?
- 获取cookie
- 获取管理员ip
- xss蠕虫
- 钓鱼攻击
- 前端JS挖矿
- 键盘记录
- 屏幕截图
XSS的分类
- 存储型 XSS
- 攻击者将恶意代码提交到目标网站的数据库中
- 用户打开目标网站时,网站服务端将恶意代码从数据库取出,拼接在 HTML 中返回给浏览器
- 用户浏览器接收到响应后解析执行,混在其中的恶意代码也被执行
- 恶意代码窃取用户数据并发送到攻击者的网站,或者冒充用户的行为,调用目标网站接口执行攻击者指定的操作
- 反射型 XSS
- 攻击者构造出特殊的 URL,其中包含恶意代码
- 用户打开带有恶意代码的 URL 时,网站服务端将恶意代码从 URL 中取出,拼接在 HTML 中返回给浏览器
- 用户浏览器接收到响应后解析执行,混在其中的恶意代码也被执行
- 恶意代码窃取用户数据并发送到攻击者的网站,或者冒充用户的行为,调用目标网站接口执行攻击者指定的操作
- DOM型 XSS
- 攻击者构造出特殊的 URL,其中包含恶意代码
- 用户打开带有恶意代码的 URL
- 用户浏览器接收到响应后解析执行,前端 JavaScript 取出 URL 中的恶意代码并执行
- 恶意代码窃取用户数据并发送到攻击者的网站,或者冒充用户的行为,调用目标网站接口执行攻击者指定的操作
三种 XSS 类型的区别
- 存储型 XSS 的恶意代码存在数据库里,反射型 XSS 的恶意代码存在 URL 里
- DOM 型 XSS 攻击中,取出和执行恶意代码由浏览器端完成,属于前端 JavaScript 自身的安全漏洞,而其他两种 XSS 都属于服务端的安全漏洞
XSS攻击的预防
- 服务器对输入脚本进行过滤或转码
- 对HTML做充分转义
- 充分利用CSP
- 输入内容长度控制
- 使用HttpOnly属性,禁止JavaScript读取某些敏感Cookie
- 使用验证码,防止脚本冒充用户提交危险操作
4、介绍CSRF攻击以及预防方案⭐⭐⭐
什么是CSRF攻击?
CSRF(Cross-site request forgery)跨站请求伪造:攻击者诱导受害者进入第三方网站,在第三方网站中,向被攻击网站发送跨站请求。利用受害者在被攻击网站已经获取的注册凭证,绕过后台的用户验证,达到冒充用户对被攻击的网站执行某项操作的目的
一个典型的CSRF攻击有着如下的流程:
- 受害者登录a.com,并保留了登录凭证(Cookie)
- 攻击者引诱受害者访问了b.com
- b.com 向 a.com 发送了一个请求:a.com/act=xx。浏览器会默认携带a.com的Cookie
- a.com接收到请求后,对请求进行验证,并确认是受害者的凭证,误以为是受害者自己发送的请求
- a.com以受害者的名义执行了act=xx
- 攻击完成,攻击者在受害者不知情的情况下,冒充受害者,让a.com执行了自己定义的操作
CSRF的类型
- GET类型的CSRF:访问带有img的页面,自动请求img url中的网站,冒充用户做某些操作
- POST类型的CSRF:访问带有自动提交的表单的页面,模拟用户完成操作
- 连接类型的CSRF:通常在论坛中发布的图片中嵌入恶意链接,或者以广告的形式诱导用户中招,攻击者通常会以比较夸张的词语诱骗用户点击,冒充用户做某些操作
CSRF的特点
- 攻击一般发起在第三方网站,而不是被攻击的网站。被攻击的网站无法防止攻击发生
- 攻击利用受害者在被攻击网站的登录凭证,冒充受害者提交操作;而不是直接窃取数据
- 整个过程攻击者并不能获取到受害者的登录凭证,仅仅是“冒用”
- 跨站请求可以用各种方式:图片URL、超链接、CORS、Form提交等等。部分请求方式可以直接嵌入在第三方论坛、文章中,难以进行追踪
CSRF通常是跨域的,因为外域通常更容易被攻击者掌控。但是如果本域下有容易被利用的功能,比如可以发图和链接的论坛和评论区,攻击可以直接在本域下进行,而且这种攻击更加危险。
CSRF的预防
- 同源检测:服务器可以通过解析HTTP请求头中的 Origin/Referer 这两个Header中的域名,来确定请求的来源域,进而阻止外域的请求
- CSRF Token
- 服务器生成加密后的CSRF Token,将其保存在Session当中,并将其输出到页面当中,利用JS遍历整个DOM树,对于所有的a和form标签加入Token
- 页面提交的请求携带这个Token
- 服务器验证Token是否正确
- 双重Cookie验证
- 在用户访问网站页面时,向请求域名注入一个Cookie,内容为随机字符串(例如
csrfcookie=v8g9e4ksfhw
) - 在前端向后端发起请求时,取出Cookie,并添加到URL的参数中(
POST https://www.a.com/comment?csrfcookie=v8g9e4ksfhw
) - 后端接口验证Cookie中的字段与URL参数中的字段是否一致,不一致则拒绝
- 在用户访问网站页面时,向请求域名注入一个Cookie,内容为随机字符串(例如
- 使用Set-Cookie响应头的 Samesite 属性,它用来标明这个 Cookie是个“同站 Cookie”,同站Cookie只能作为第一方Cookie,不能作为第三方Cookie,Samesite 有三个属性值,分别是 Strict 、 Lax 、 None
- Strict最为严格。如果SameSite的值是Strict,那么浏览器会完全禁止第三方 Cookie
- Lax相对宽松一点。在跨站点的情况下,从第三方站点的链接打开和从第三方站点提交Get方式的表单这两种方式都会携带Cookie。但如果在第三方站点中使用Post方法,或者通过img、iframe等标签加载的URL,这些场景都不会携带Cookie
- 如果使用None的话,在任何情况下都会发送Cookie
- 保证页面的幂等性,后端接口不要在GET页面中做用户操作
5、从输入URL到页面显示的过程⭐⭐
简单版过程:
- 浏览器地址栏输入 URL 并回车
- 浏览器查找当前 URL 是否存在缓存,并比较缓存是否过期
- DNS 解析 URL 对应的 IP
- 根据 IP 建立 TCP 连接(三次握手)
- 发送 http 请求
- 服务器处理请求,浏览器接受 HTTP 响应
- 浏览器解析并渲染页面
- 关闭 TCP 连接(四次握手)
正向代理与反向代理
正向代理:服务于客户端,隐藏客户端,代替客户端去请求服务器,服务器不知道这个请求是从哪个客户端发起的
反向代理:服务于服务器,隐藏服务器,客户端直接请求反向代理服务器拿到数据就行了,客户端不知道数据是哪个服务器处理的
Http缓存相关header
Expires
响应头,代表该资源的过期时间。
Cache-Control
请求/响应头,缓存控制字段,精确控制缓存策略。
If-Modified-Since
请求头,资源最近修改时间,由浏览器告诉服务器。
Last-Modified
响应头,资源最近修改时间,由服务器告诉浏览器。
Etag
响应头,资源标识,由服务器告诉浏览器。
If-None-Match
请求头,缓存资源标识,由浏览器告诉服务器。
配对使用的字段:
- Last-Modified 和 If-Modified-Since
-
六、HTTP与计算机网络
1、HTTP有哪些优点?哪些缺点?⭐⭐
优点:
简单、灵活、易扩展
- 应用广泛,有成熟的基础设施
- http是无状态的,可以轻松实现集群化、扩展性能,同时也需要用cookie来实现“有状态”
缺点:
- http是明文传输,数据完全暴露,容易被截取和分析
- http是不安全的,无法验证通信双方的身份(无状态),无法判断报文是否被篡改(明文传输)
http性能不算太好,会导致“队头阻塞”的问题(由于“请求-响应”的模式,当请求序列中有一个请求被阻塞了,会导致后面排队的所有请求全部被阻塞,导致客户端接收不到数据)
2、HTTP/1.0、HTTP/1.1、HTTP/2.0的特点和区别⭐⭐⭐
HTTP/1.0
增加了HEAD、POST等新方法
- 增加了响应状态码,标记可能的错误原因
- 引入了协议版本号概念
- 引入了HTTP Header(头部)的概念,让HTTP处理请求和响应更加灵活
- 传输的数据不再仅限于文本,还包括图片、音频等
- HTTP/1.0并不是一个“标准”,相当于一个“备忘录”
HTTP/1.1
- 长连接:支持TCP复用,通过http/1.1的Connection字段设置为keep-alive,表示开启长连接,即一个TCP连接不关闭,可以发送多个http请求
- 并发连接:对一个域名的请求允许分配多个长连接
- 同一 GET 请求的并发数量是1
- 不同 GET/POST 请求的并发数量是6
- 管道机制:一个TCP连接允许同时发送多个请求,不过是串行的发送请求,一个个发,响应也是按顺序串行发回
- 增加了PUT、DELETE等新的方法
- 增加了缓存管理和控制
- 允许响应数据分块(chunked),利于传输大文件
- 强制要求Host头,让互联网主机托管成为可能
- HTTP/1.1 是一个“正式的标准”
HTTP/2.0
- 二进制分帧,将原来的 Header + body 的报文格式拆分成一个个二进制的帧,用 Header帧存放头部字段,Data帧存放请求体数据
- 头部压缩,使用HPACK算法,对请求头进行压缩
- 在服务器和客户端之间建立哈希表,将用到的字段放到表中,传输的时候对于之前出现过的值,只需要把索引传给对方,对方拿到索引查表即可。
- 通过哈夫曼编码对传输的首部字段进行编码,提高压缩率
- 原理就是先将所有出现的字符建立一张索引表,然后让出现次数多的字符对应的索引尽可能短
- 多路复用,一个TCP连接上可以有任意多个流(stream),将消息分割成一个或多个帧在流里面传输。帧传输过去后,再进行重组,形成一个完整的请求或响应,从而解决http队头阻塞的问题
服务器推送,服务器端可以预测客户端需要的资源,主动地推送给客户端。比如:浏览器请求一个html文件,服务器可以在返回html的基础上,将html所引用到的其它资源一起返回给客户端,减少客户端的等待
3、HTTPS和HTTP的区别⭐⭐
http是明文传输不安全,https会对数据进行加密安全性较好
- https协议需要到ca申请证书,一般免费证书较少,因而需要一定费用
- http和https使用的是完全不同的连接方式,用的端口也不一样,前者是80,后者是443
- HTTP 页面响应速度比 HTTPS 快(主要是因为 HTTP 使用 TCP 三次握手建立连接,客户端和服务器需要交换 3 个包,而 HTTPS除了 TCP 的三个包,还要加上 ssl 握手需要的 9 个包,所以一共是 12 个包)
-
4、HTTPS的加密原理⭐⭐⭐
对称加密:采用单钥系统的加密方式,同一个密钥可以用作信息的加密和解密
优点: 用户只需要记住一个密钥即可加密与解密
- 与非对称加密对比,对称加密加密速度快、计算量小、简单易用
缺点:
- 无法保证将密钥安全送达对方
- 每对用户每次使用对称加密算法时,都需要使用与其他人不知道的唯一秘钥,这会使得收、发方都会保留大量的秘钥,管理起来十分麻烦,会加大双方的负担
非对称加密:加密和解密使用不同的秘钥,有公钥和私钥,公钥加密,私钥解密;私钥加密,公钥解密;私钥只能由一方安全保管不能外泄,而公钥可以发给任何请求它的人。
优点:安全性高,公钥是公开的,私钥由自己保存不需要给别人
缺点:加密和解密花费时间长,速度慢,只适合对少量数据加密
5、三次握手和四次挥手⭐⭐⭐
三次握手
- 第一次握手:客户端发送SYN包(SYN=1、seq=x)给服务器发起握手,客户端进入SYN-SENT(同步已发送)状态
- 第二次握手:服务器收到客户端发送的SYN包后,向客户端发送确认,发送SYN包和ACK包(SYN=1、ACK=1、seq=y、ack=x+1),服务器进入SYN-RCVD(同步收到)状态
- 第三次握手:客户端收到服务器的SYN+ACK包之后,向服务器给出确认,发送ACK包(ACK=1,seq=x+1,ack=y+1),客户端进入ESTABLISHED(已建立连接)状态,服务器收到确认包之后也进入ESTABLISHED状态,完成三次握手
四次挥手
- 客户端进程发出连接释放报文,并且停止发送数据。释放数据报文首部,FIN=1,其序列号为seq=u,此时,客户端进入FIN-WAIT-1(终止等待1)状态
- 服务器收到连接释放报文,发出确认报文,ACK=1,ack=u+1,并且带上自己的序列号seq=v,此时,服务端就进入了CLOSE-WAIT(关闭等待)状态。TCP服务器通知高层的应用进程,客户端向服务器的方向就释放了,这时候处于半关闭状态,即客户端已经没有数据要发送了,但是服务器若发送数据,客户端依然要接受。这个状态还要持续一段时间,也就是整个CLOSE-WAIT状态持续的时间
- 客户端收到服务器的确认请求后,此时,客户端就进入FIN-WAIT-2(终止等待2)状态,等待服务器发送连接释放报文
- 服务器将最后的数据发送完毕后,就向客户端发送连接释放报文,FIN=1,ack=u+1,由于在半关闭状态,服务器很可能又发送了一些数据,假定此时的序列号为seq=w,此时,服务器就进入了LAST-ACK(最后确认)状态,等待客户端的确认
- 客户端收到服务器的连接释放报文后,必须发出确认,ACK=1,ack=w+1,而自己的序列号是seq=u+1,此时,客户端就进入了TIME-WAIT(时间等待)状态。注意此时TCP连接还没有释放,必须经过2MSL(最长报文段寿命)的时间后,当客户端撤销相应的TCB后,才进入CLOSED状态
服务器只要收到了客户端发出的确认,立即进入CLOSED状态。同样,撤销TCB后,就结束了这次的TCP连接。可以看到,服务器结束TCP连接的时间要比客户端早一些
6、UDP和TCP的区别以及应用场景⭐
区别:
TCP是面向连接的,而UDP是面向无连接的
- TCP仅支持一对一通信,而UDP支持一对一、一对多、多对多、多对一的通信
- TCP连接是可靠的,能使用拥塞控制和流量控制,而UDP链接是不可靠的
- TCP传输面向字节流,而UDP传输面向报文
- UDP的头部开销比TCP更小,数据传输速率更高,实时性更好
UDP应用场景:适用于实时应用(IP电话、视频会议、直播等)
TCP应用场景:适用于要求可靠传输的应用,例如文件传输
7、介绍一下cookie⭐⭐
8、GET和POST的区别⭐⭐⭐
相同点:
- GET和POST本质都是TCP连接
不同点:
- GET多用于从服务器获取资源,POST一般向服务器提交资源
- GET的参数通过URL传递,POST的参数放在
request.body
中 - GET参数暴露在地址栏不安全,POST放在报文内部更安全
- GET请求在URL中传送的参数是有长度限制的(由浏览器对URL长度限制决定),而POST没有限制
- GET请求只能进行URL编码,而POST支持多种编码方式
- GET参数类型只支持ASCII字符,而POST没有限制
- GET 请求会被浏览器主动cache,而 POST 不会,除非手动设置
- GET 请求参数会被完整保留在浏览器历史记录里,而 POST 中的参数不会被保留
- GET 请求的地址可被收藏为书签,而 POST 不可以
- GET 在浏览器回退时不会再次请求,而 POST 会再次提交请求
- GET 产生一个 TCP 数据包,而POST 产生两个 TCP 数据包
9、HTTP缓存⭐⭐
http缓存机制可以加快资源获取速度,提升用户体验,减少网络传输,缓解服务器压力,主要缓存一些静态资源比如js、css、图片
http缓存一般分为强缓存和协商缓存
强缓存流程:
- 浏览器第一次请求页面,服务器进行响应,浏览器会根据响应头中的字段来判断是否对资源进行缓存,如果响应头中通过
Expires
、Cache-Control
字段设置了资源过期时间,则表示设置了强缓存,浏览器就会把资源进行缓存 - 浏览器再次请求时,会根据字段值判断当前资源是否过期,如果没有过期直接返回200,并使用本地缓存的数据;否则会使用协商缓存
Expires 和 Cache-Control 的区别
- Expires 是HTTP/1.0中的,Cache-Control 是HTTP/1.1中的
- Expires 是为了兼容,在不支持 HTTP/1.1 的情况下才会发生作用
- 两者同时存在的话 Cache-Control 优先级高于 Expires
协商缓存主要通过Last-modified
/If-Modified-Since
、Etag
/If-None-Match
两对字段来设置协商缓存
- 第一次请求页面服务器除了会在响应头中设置
Expires
、Cache-Control
字段还会设置Last-modified
和Etag
字段,Last-modified
字段表示的是资源的最后修改时间,而Etag
字段表示的是当前资源文件的唯一标识,Etag
字段的优先级要高于Last-modified
字段 - 当强缓存未命中时,浏览器会在请求头中通过
If-Modified-Since
字段设置资源的最后修改时间,以及通过If-None-Match
字段来设置当前资源文件的唯一标识;服务器会优先判断Etag
/If-None-Match
这一对字段,否则判断Last-modified
/If-Modified-Since
这一对,如果命中协商缓存,则会返回304,告诉浏览器资源内容未改变或资源未发生修改,使用本地缓存即可,若未命中,则返回200,并将最新的资源返回
Last-Modified的缺点
- 如果本地打开了缓存文件,即使没有对文件进行修改,但还是会造成
Last-Modified
被修改,服务器端不能命中缓存导致发送相同资源 - 因为
Last-Modified
只能以秒计时,如果在不可感知的时间内修改了文件,服务器端会认为还是命中了,无法返回正确的资源 - 如果资源有周期性变化,如资源修改后,在一个周期内又改回了原来的样子,我们认为这个周期前的缓存是可以使用的,但是
Last-Modified
不这样认为
Last-Modified 和 ETag 的区别
- Etag 感知文件精准度要高于 Last-Modified
- 同时使用时,服务器校验优先级 Etag/If-None-Match
Last-Modified 性能上要优于 Etag,因为 Etag 生成过程中需要服务器付出额外开销,会影响服务器端的性能,所以它并不能完全替代 Last-Modified,只能作为补充和强化
10、OSI七层协议分别是什么?每一层的功能
七、框架(Vue)
1、Vue2和Vue3的区别⭐⭐
2、Vue的响应式原理⭐⭐⭐
在vue2中是使用Object.defineProperty去拦截对象中属性的getter和setter,为每一个属性分配一个dep数组存放watcher依赖,当获取元素时会调用getter中的方法,将watcher添加到dep中(会保证watcher唯一),当属性发生改变时,触发setter,通知所有的订阅者,将dep中的watcher遍历执行,响应式更新视图,实现双向绑定
而vue3中则是通过proxy代理整个对象的方式实现,也是通过拦截属性的getter和setter,获取时收集依赖,修改时触发依赖,不过vue3的proxy能够代理整个对象,无需向vue2一样需要通过遍历的方式拦截对象的每个属性3、Diff算法了解吗?介绍一下Vue的Diff算法⭐⭐⭐
4、模板编译原理
5、nextTick原理
6、keep-alive原理⭐⭐
对keep-alive的介绍
keep-alive是Vue内置的一个组件,可以实现组件缓存,当组件切换时能够保留组件的状态,避免重新渲染一般结合路由和动态组件一起使用,用于缓存组件
- 主要有include、exclude、max三个属性
- include 和 exclude 允许 keep-alive 有条件的进行缓存,匹配 include 的组件会被缓存,而匹配exclude的组件不会被缓存,其中 exclude 优先级高于 include
- max属性可以定义组件最大缓存个数,如果超过这个个数,会使用 LRU 置换策略删除最近最久未使用的实例
- 对应两个生命周期钩子
activated/deactivated
,当组件激活的时候触发activated
钩子函数,当组件切换时调用deactivated
钩子函数 - keep-alive 利用 abstract 属性,使得组件本身不会被渲染,且不会出现在父组件链中
keep-alive原理
- 获取 keep-alive 包裹的第一个子组件对象以及其组件名;如果 keep-alive 存在多个子元素,keep-alive 要求同时只有一个子元素被渲染。所以在开头会获取插槽内的子元素,调用 getFirstComponentChild 获取到第一个子元素的 VNode
- 根据设定的黑白名单(如果有)进行条件匹配,决定是否缓存。如果不匹配,则直接返回组件实例(VNode),否则开启缓存策略
- 根据组件 ID 和 tag 生成缓存 Key ,并在缓存对象中查找是否已缓存过该组件实例。如果存在,直接取出缓存值并更新该 key 在 this.keys 中的位置(更新 key 的位置是实现 LRU 置换策略的关键)
- 如果不存在,则在 this.cache 对象中存储该组件实例并保存 key 值,之后检查缓存的实例数量是否超过max设置值,超过则根据 LRU 置换策略删除最近最久未使用的实例(即是下标为0的那个key)。最后将该组件实例的 keepAlive 属性值设置为 true
7、v-if和v-show的区别⭐⭐
区别:
v-if是真正的条件渲染,它会确保会确保在切换过程中条件块内的事件监听器和子组件适当地被销毁和重建;也是惰性的:如果在初始渲染时条件为假,则什么也不做——直到条件第一次变为真时,才会开始渲染条件块
v-show则是不管什么情况下元素都会被渲染,而v-show的条件只是切换display
的属性,从而实现元素的显隐
应用场景:
v-if 适用于在运行时很少改变条件,不需要频繁切换条件的场景;v-show 则适用于需要非常频繁切换条件的场景8、computed和watch的区别⭐⭐
区别:
computed是计算属性,会根据所依赖的响应式数据派生出一个新的数据,computed中的函数必须使用return返回结果;它会将计算结果进行缓存,如果所依赖的响应式数据没有发生变化,那么computed每次都返回缓存的数据,只有当依赖发生变化时才重新计算
watch是侦听器,它可以侦听某个响应式数据的变化并执行副作用函数,watch没有返回值,可以执行异步任务;watch默认第一次加载不做监听,如果需要第一次加载做监听,设置immediate:true即可9、history 和 hash 两种路由方式的特点⭐
10、简述MVVM⭐
MVVM是Model-View-ViewModel缩写,也就是把MVC中的Controller演变成ViewModel。Model层代表数据模型,View代表UI组件,ViewModel是View和Model层的桥梁,数据会绑定到viewModel层并自动将数据渲染到页面中,视图变化的时候会通知viewModel层更新数据11、组件中data为什么是一个函数?⭐
因为组件是用来复用的,如果data是一个对象,那么每个组件实例的data都指向同一块内存地址,修改属性值会相互影响,造成变量污染;如果data是一个函数,那么每个组件实例都会维护一份属于自己的对象,组件实例之间的data属性不会相互影响12、v-model的原理⭐⭐
v-model本质上是v-bind和v-on的语法糖,在默认情况下相当于value属性的绑定以及input事件监听,对于不同的表单元素会有不同的属性和事件对
- text和textarea元素使用value属性和input事件
- checkbox和radio使用check属性和change事件
- select使用value属性和change事件
在组件上可以利用prop和emit的方式绑定组件内的表单元素,实现双向绑定
13、组件通信的几种方式⭐⭐
父子组件通信
- props/$emit
- ref 访问 DOM 元素或子组件实例
- $parent / $children
跨代组件通信
- eventbus
- provide/inject
-
14、了解SPA吗?详细介绍一下⭐
什么是SPA
SPA就是单页面应用,服务器一次性把页面所需的资源发送给客户端,在客户端进行渲染,之后的页面切换也只是路由切换,不需要刷新整个页面,实现无刷新切换技术
SPA原理
SPA原理使用 history 和 hash 两种路由方式实现,因为切换路由时不会向服务器发送请求
SPA优点 页面切换很快,无需发送http请求
- 用户体验好
SPA缺点
- 首屏加载速度慢,因为第一次请求时除了请求html,还需要请求js,两次请求之后解析并渲染才会再页面显示
不易于SEO,因为搜索引擎需要根据html中的信息去识别,而单页面应用只有一个html,其它页面是靠js渲染生成通过路由进行切换,这样会导致SEO识别不出来其它页面内容,导致在搜索时的排名差
15、服务端SSR了解吗?⭐
SSR也就是服务端渲染,将Vue在客户端html渲染的工作放到服务端完成,服务端把渲染后的html返回给客户端进行展示
SSR的优点:有着更好的SEO、首屏加载速度更快
SSR的缺点:开发环境会受到限制,服务端SSR只支持
beforeCreate
和created
两个生命周期钩子,需要一些外部扩展库来进行扩展- 服务端渲染应用程序需要运行在Node.js环境中
- 服务器会有更大的负载需求
八、前端工程化
1、前端工程化的流程
2、Webpack执行原理
3、Plugin 和 Loader 的区别
4、说一下git常用命令,正常开发中使用了哪些git操作
九、优化
1、用户体验优化⭐
- 白屏时的loading动画
- 骨架屏
渐进式加载内容(懒加载)
代码压缩:
- 使用webpack进行代码压缩
- 使用
image-webpack-loader
对图片进行压缩或者用tinify对图片进行压缩 - 使用
terser-webpack-plugin
压缩 Javascript 代码 - 使用
css-minimizer-webpack-plugin
压缩 CSS 代码 - 使用
html-webpack-plugin
压缩 html 代码
- 使用
- 开启gzip压缩,webpack 中使用
compression-webpack-plugin
开启gzip,服务器也要进行配置开启gzip
- 使用webpack进行代码压缩
- 使用
externals
分离第三方资源包(如:Vue、Element-UI等),使用CDN的方式引入 - 生产环境关闭
sourcemap
- 前端路由懒加载
- 配置
SplitChunks
抽取公有代码 - 引入第三方库时使用按需引入
其它:
防抖和节流(resize,scroll,input)
- 减少重排、重绘
- 减少 DOM 操作
- 使用事件委托
- 合理使用v-if和v-show
- 合理使用watch和computed
- 使用v-for必须添加key,最好为唯一id,避免使用index,且在同一个标签上v-for不要和v-if同时使用
4、白屏优化