1. 什么是作用域?
变量 产生作用的区域就叫做作用域
2. 作用域的分类
全局作用域
局部作用域
3.局部作用域的分类
函数作用域
块级作用域
4.作用域链
作用域链的本质是变量查找机制
5.作用域链查找规则是什么?
a. 会优先查找自己的作用域
b. 自己的作用域查找不到的话会往上查找父级直到全局作用域
6.什么是垃圾回收机制
是 JS
中一种自动回收或释放内存的机制 简称 GC
7.垃圾回收机制有几种算法?
引用计数法:IE采用的引用计数算法, 定义“内存不再使用
”的标准很简单,就是看一个对象是否有指向它的引用
如果这个值的被引用了一次,那么就记录次数1 , 如果减少一个引用就减1。 如果引用次数是0 ,则释放内存。但它却存在一个致命的问题:嵌套引用。
标记清除法:就是从根部
(在JS中就是全局对象)出发定时扫描内存中的对象。 凡是能从根部到达的对象,都是还需要使用的。
无法由根部出发触及到的对象被标记为不再使用,稍后进 行回收
8.什么是闭包?
就是有权访问另一个函数作用域中变量的函数
9.闭包的表现形式?
在一个函数内部创建另外一个函数
10.闭包有什么作用?
封闭数据,实现数据私有,防止数据被意外修改
11.闭包的弊端
容易导致内存泄露
12.什么是变量提升?
使用 var
声明的变量,会被提升到函数或全局作用域的顶部,这个现象叫做变量提升。
13.用哪个关键词会产生变量提升?
var
会存在变量提升,let/const
声明的变量不存在变量提升
14.什么是构造函数
是一种特殊的函数,主要用来初始化对象 ,同时可以用构造函数来快速创建多个类似的对象。
15.构造函数创建对象的过程
- 创建新对象
- 构造函数this指向新对象
- 执行构造函数代码,修改this,添加新的属性
- 返回新对象
16.伪数组转真数组的方法
1.Array.from
2.Array.prototype.slice.call( )
3…展开运算符
17.什么是JavaScript 中的包装类型
在 JavaScript
中,基本类型是没有属性和方法的,但是为了便于操作基本类型的值,在调用基本类型的属性或方法时 JavaScript
会在后台地将基本类型的值转换为对象,这些对象就是包装类型
18. JavaScript有哪些数据类型,它们的区别?
JavaScript
共有八种数据类型,分别是 Undefined、Null、Boolean、Number、String、Object、Symbol、BigInt
。
其中 Symbol
和 BigInt
是 ES6 中新增的数据类型
Symbol
代表创建后独一无二且不可变的数据类型,它主要是为了解决可能出现的全局变量冲突的问题。
BigInt
是一种数字类型的数据,它可以表示任意精度格式的整数,使用 BigInt
可以安全地存储和操作大整数,即使这个数已经超出了 Number 能够表示的安全整数范围。
这些数据可以分为原始数据类型和引用数据类型:
栈:原始数据类型(Undefined、Null、Boolean、Number、String、Symbol 、BigInt
)
堆:引用数据类型(对象、数组和函数)
19.isNaN 和 Number.isNaN 函数的区别
重点在于判断 是不是NaN,而不是 数字
- 函数
isNaN
接收参数后,会尝试将这个参数转换为数值,任何不能被转换为数值的的值都会返回true
,因此非数字值传入也会返回true
,会影响NaN
的判断。 - 函数
Number.isNaN
只会判断 传入的数据 是不是 一个NaN
,并且不会帮你做类型转换。
20.对原型、原型链的理解
原型,也叫原型对象,构造函数的一个属性,名字是 prototype
,它本身也是一个对象类型。在构造函数的原型所添加的成员可以被实例所共享。
原型链,指的基于原型继承的那些对象中,它们是通过 原型 prototype
将彼此联系在一起的,这个关系就叫做原型链。
21.原型链-查找规则
① 当访问一个对象的属性(包括方法)时,首先查找这个对象自身有没有该属性。
② 如果没有就查找它的原型(也就是 proto
指向的 prototype
原型对象)
③ 如果还没有就查找原型对象的原型(Object的原型对象)
④ 依此类推一直找到 Object
为止(null)
⑤ proto
对象原型的意义就在于为对象成员查找机制提供一个方向,或者说一条路线
22.什么是递归
函数内部自己调用自己, 这个函数就是递归函数,往往都需要添加终止递归的条件。
23.什么是深拷贝 什么是浅拷贝
-
浅拷贝只是针对引用类型数据中的属性做了一层复制,如果被拷贝的属性也是引用类型,那么这个属性只是复制了这个引用地址。
做了浅拷贝的对象之间可能会相互影响
-
深拷贝是针对引用类型数据中的属性做无限层级的复制,不管属性是值类型还是引用类型,会完整复制一份。 其在堆内存中完全开辟了一块内存地址,并将原有的对象完全复制过来存放
做了深拷贝的两个对象之间相互不会影响
-
除了 递归克隆对象、
JSON.stringify
两种方式做的拷贝,其他方法全部都是浅拷贝
24.call、apply、bind的区别
- 他们三都可以修改
this
指向, call、apply
在修改 this 指向的同时也会调用原函数、bind
只会返回修改 this 指向后的函数call
和apply
接收参数的方式不一样,call
类似普通函数一样接收参数、apply
接收的参数必须都放在一个数组内。
25.什么是防抖和节流
- 所谓节流,就是在连续触发的行为中控制它在 n 秒中只执行一次 可以用在 轮播图点击效果 、 鼠标移动、页面尺寸缩放 resize、滚动条滚动 等场景
- 所谓防抖,在单位时间内,某个动作只能执行一次,如果在单位时间内多次触发,那么只有最后一次有效,可以用在 搜索框 业务中。
二、Ajax面试题
26.HTTP 状态码
成功(2XX)
状态码 | 原因短语 | 说明 |
---|---|---|
200 | OK | 表示从客户端发来的请求在服务器端被正确处理 |
201 | Created | 请求已经被实现,⽽且有⼀个新的资源已经依据请求的需要⽽建⽴ 通常是在POST请求,或是某些PUT请求之后创建了内容, 进行的返回的响应 |
202 | Accepted | 请求服务器已接受,但是尚未处理,不保证完成请求 适合异步任务或者说需要处理时间比较长的请求,避免HTTP连接一直占用 |
204 | No content | 表示请求成功,但响应报⽂不含实体的主体部分 |
206 | Partial Content | 进⾏的是范围请求, 表示服务器已经成功处理了部分 GET 请求 响应头中会包含获取的内容范围 (常用于分段下载) |
重定向(3XX)
状态码 | 原因短语 | 说明 |
---|---|---|
301 | Moved Permanently | 永久性重定向,表示资源已被分配了新的 URL 比如,我们访问 http😕/www.baidu.com 会跳转到 https😕/www.baidu.com |
302 | Move Temporarily | 临时性重定向,表示资源临时被分配了新的 URL, 支持搜索引擎优化 首页, 个人中心, 遇到了需要登录才能操作的内容, 重定向 到 登录页 |
303 | See Other | 对于POST请求,它表示请求已经被处理,客户端可以接着使用GET方法去请求Location里的URI。 |
304 | Not Modified | 自从上次请求后,请求的网页内容未修改过。 服务器返回此响应时,不会返回网页内容。(协商缓存) |
307 | Temporary Redirect | 对于POST请求,表示请求还没有被处理,客户端应该向Location里的URI重新发起POST请求。 不对请求做额外处理, 正常发送请求, 请求location中的url地址 |
客户端错误(4XX)
状态码 | 原因短语 | 说明 |
---|---|---|
400 | Bad Request | 请求报⽂存在语法错误((传参格式不正确) |
401 | UnAuthorized | 权限认证未通过(没有权限) |
403 | Forbidden | 表示对请求资源的访问被服务器拒绝 |
404 | Not Found | 表示在服务器上没有找到请求的资源 |
408 | Request Timeout | 客户端请求超时 |
409 | Confict | 请求的资源可能引起冲突 |
服务端错误(5XX)
状态码 | 原因短语 | 说明 |
---|---|---|
500 | Internal Sever Error | 表示服务器端在执⾏请求时发⽣了错误 |
501 | Not Implemented | 请求超出服务器能⼒范围,例如服务器不⽀持当前请求所需要的某个功能, 或者请求是服务器不⽀持的某个⽅法 |
503 | Service Unavailable | 表明服务器暂时处于超负载或正在停机维护,⽆法处理请求 |
505 | Http Version Not Supported | 服务器不⽀持,或者拒绝⽀持在请求中使⽤的 HTTP 版本 |
27. DOM - 事件流与事件委托
2.1 事件流
事件流:又称为事件传播,是页面中接收事件的顺序。DOM2级事件规定的事件流包括了3个阶段:
- 事件捕获阶段(capture phase)
- 处于⽬标阶段(target phase)
- 事件冒泡阶段(bubbling phase)
事件捕获(Event Capturing)
事件开始由较为不具体的节点接收后,然后开始逐级向下传播到最具体的元素上。
事件捕获的最大作用在于:事件在到达预定⽬标之前就可以捕获到它。
如果仍以上面那段 HTML 代码为例,当点击按钮后,在事件捕获的过程中,document 对象会首先接收到这个 click
事件,然后再沿着 DOM 树依次向下,直到 <button>
。具体顺序如下:
- document 对象
- html 元素
- body 元素
- button 元素
事件冒泡(Event Bubbling)
事件开始由最具体的元素(⽂档中嵌套层次最深的那个节点)接收到后,开始逐级向上传播到较为不具体的节点。
<html>
<head>
<title>Document</title>
</head>
<body>
<button>按钮</button>
</body>
</html>
如果点击了上面页面代码中的 <button>
按钮,那么该 click
点击事件会沿着 DOM 树向上逐级传播,在途经的每个节点上都会发生,具体顺序如下:
- button 元素
- body 元素
- html 元素
- document 对象
2.2 事件委托
事件委托: 利用了事件冒泡的机制,在较上层位置的元素上添加一个事件监听函数,来管理该元素及其所有子孙元素上的某一类的所有事件。
示例
<ul id="list">
<li>111</li>
<li>222</li>
<li>333</li>
<li>444</li>
<li>555</li>
</ul>
<script type="text/javascript">
// ⽗元素
var list = document.getElementById('list');
// 为⽗元素绑定事件,委托管理它的所有⼦元素li的点击事件
list.onclick = function (event) {
var currentTarget = event.target;
if (currentTarget.tagName.toLowerCase() === 'li') {
alert(currentTarget.innerText)
}
}
</script>
适用场景:在绑定大量事件的时候,可以选择事件委托
优点
- 事件委托可以减少事件注册数量,节省内存占⽤!
- 当新增⼦元素时,⽆需再次做事件绑定,因此非常适合动态添加元素 (vue解析模板时, 会对新创建的元素, 额外进行绑定的)
28. Post 请求中 Content-Type 有哪几种类型?分别有什么特点?
主要有以下三种:
application/x-www-form-urlencoded
: 原生的 form 表单提交数据,数据会进行编码,较少使用multipart/form-data
:可以上传键值对,也可以上传文件application/json
:以 JSON 字符串的格式传递,效率较高,经常使用
问:如何设置这三种数据类型?
- urlencoded:使用
encodeURIComponent()
- formData: 使用
new FormData()
- json: 使用
JSON.stringify()
29 . FormData 对象是什么?有哪些 API?
FormData 是一个以 key/value 形式存储数据的对象,可以实现表单数据的序列化,包括普通的字符串、文件等,主要通过 Ajax 发送表单数据,可以进行二进制的文件进行上传文件
new FormData()
:创建一个新的 FormData 对象,- 参数为空时,创建一个空的 FormData 对象
- 参数为 form 元素时,创建一个包含表单元素各项值的 FormData 对象,详情见示例
FormData.append(key, val)
:向 FormData 中添加新的属性值,FormData 对应的属性值存在也不会覆盖原值,而是新增一个值,如果属性不存在则新增一项属性值FormData.set(key, val)
:给 FormData 设置属性值,如果FormData 对应的属性值存在则覆盖原值,否则新增一项属性值FormData.get(key)
:返回在 FormData 对象中与给定键关联的第一个值FormData.delete(key)
:从 FormData 对象里面删除一个键值对FormData.keys()
: 返回一个包含所有键的 iterator 对象FormData.values()
: 返回一个包含所有值的 iterator 对象FormData.entries()
: 返回一个包含所有键值对的 iterator 对象
30 . promise 有哪些常用的方法?作用分别是什么?
当我们在构造 Promise 的时候,构造函数内部的代码是立即执行的:
Promise.prototype.then()
:为 Promise 实例添加状态改变时的回调函数- .then() 的第一个参数为成功时的回调
- .then() 的第二个参数为失败时的回调
- 返回值为一个新的 promise
Promise.prototype.catch()
:用于指定发生错误时的回调函数- 作用与
.then(undefined, fn)
一样 - 返回值为一个新的 promise
- 作用与
Promise.all()
: 获取所有的成功结果,或最先失败的结果- 接收一个数组作为参数,如果数组项不是 promise 对象,则转换为 promise 对象
- 返回值为一个新的 promise,promise 的状态可分为如下两种情况:
- 所有 promise 对象 resolved 时,才 resolved
- 只要有一个 promise 对象 rejected 时,就 resolved
Promise.race()
: 获取最快的一个 promise 结果, 不论成功或失败- 接收一个数组作为参数,如果数组项不是 promise 对象,则转换为 promise 对象
- 返回值为一个新的 promise,promise 的状态以传入数据的状态为准
- 但凡有一个 promise 为 resolved,就 resolved
- 但凡有一个 promise 为 rejected,就 rejected
31. 什么是链式调用?为什么能用链式调用?
链式调用:在调用对象上的某个方法之后,还可以接着调用其他方法,如 [1,2,3].map().filter().concat()
、axios({}).then().catch()
原因:方法的返回值是一个对象,对象上拥有某些方法,所以可以接着一直调用
promise 对象为什么可以链式调用
Promise
对象的原型上有then()
方法,可以被调用then()
方法的返回值是一个新的Promise
对象 ,状态是 pending- 所以
Promise
最终可形成.then().then().....
这种链式结构 promise
的状态没有改变,不会执行then
里面的代码
问题:如何实现一个 Person,可以满足以下的方式链式调用
person.setName('Jack').setAge(18).sayHi().sleep()
// 待实现代码
function Person() {
this.name = '机器人1号'
this.age = 100
}
// 待实现代码
Person.prototype.setName = function(name) {
this.name = name
return this
}
Person.prototype.setAge = function(age) {
this.age = age
return this
}
Person.prototype.sayHi = function() {
console.log(`name: ${this.name} , age: ${this.age}`)
return this
}
Person.prototype.sleep = function() {
console.log('sleep')
return this
}
const person = new Person()
person.setName('Jack').setAge(18).sayHi().sleep()
32 . 实现异步编程的方式有哪些?分别有哪些特点?
- 回调函数
- 写法:
setTimeout(() => {}, 1000)
、ele.addEventListener('click', () => {})
- 特点:将函数作为参数传入,并在特定的时机被调用,比较简单
- 说明:多个回调函数嵌套的时候会造成回调函数地狱,耦合度太高,不利于维护
- 写法:
- promise
- 写法:
promise.then(() => {...})
- 特点:可以将嵌套的回调函数作为链式调用,可维护性增强
- 说明:有时会造成多个 then 的链式调用,可能会造成代码的语义不够明确
- 写法:
- async 异步函数
async
声明的异步函数,它的返回值会自动包装为promise
async
声明的异步函数中可以使用await
来调用其他异步函数- 调用
await
,它会等待promise
执行出结果后将结果返回,可以通过变量接收结果 -
- 写法:
async function () { await asyncFn() }
- 特点:将异步逻辑,转化为同步的顺序书写,更简洁,推荐使用
- 说明:当函数内部执行到一个 await 语句的时候,如果语句返回一个 promise 对象,那么函数将会等待 promise 对象的状态变为 resolve 后再继续向下执行
- 写法:
33 . 浏览器的事件循环机制是什么?执行流程是怎样的?
JavaScript 在设计之初便是单线程,即指程序运行时,只有一个线程存在,同一时间只能做一件事,为了解决单线程运行阻塞问题,JavaScript 用到了计算机系统的一种运行机制,这种机制就叫做事件循环(Event Loop)
如果 JS 设置为多线程,一个线程进行了删除 DOM ,另一个添加 DOM,会导致很多数据和页面更新的问题
在 JavaScript 中,所有的任务都可以分为:
- 同步任务:立即执行的任务,同步任务一般会直接进入到主线程中执行
- 异步任务:异步执行的任务,比如ajax网络请求,setTimeout 定时函数等
微任务和宏任务在浏览器的执行顺序:
- 执行一个宏任务
- 执行完微任务队列
- 重复上面的步骤…
微任务和宏任务的调度机制也被称作为事件循环机制 EventLoop
- 宏任务 macrotask:
- script (可以理解为外层同步代码)
- setTimeout
- setInterval
- Ajax
- 浏览器触发的 DOM 事件(如 click、resize)
- postMessage
- MessageChannel
- 微任务 microTask:
- promise.then
- MutationObserver
- queueMicrotask
在代码执行的过程中,同步任务会立即执行,异步任务会通过一些手段和过程才会拿到结果。所以在异步任务等待结果的同时,可先执行其后的同步任务。当异步任务有结果的时候,在回过头来执行异步任务
EvnentLoop执行的机制就是先执行同步代码,接着是微任务,然后是宏任务。
三、git面试题
34. Git和其他代码管理版本控制系统有什么区别?
Git 和其他版本代码管理控制系统( 如 SVN 和 CVS )之间的主要区别在于它们的架构和工作方式。Git 是一个分布式版本控制系统,每个开发人员都可以拥有一个完整的代码库副本,并在需要时进行合并更改。
而 SVN 和 CVS 等传统的版本控制系统是基于中央服务器的,每个开发人员都从中央服务器检出代码,然后提交更改
35. Git的三个区域是什么?如何将代码从一个区域移动到另一个区域?
Git的三个区域是工作区、暂存区和本地仓库。可以通过git add
将代码从工作区移动到暂存区,通过git commit
将代码从暂存区移动到本地仓库
36. 如何将本地的代码推送到远程仓库?
可以通过git push
将本地的代码推送到远程仓库。例如,可以使用git push origin master
将本地的master分支推送到名为origin的远程仓库。
37. 如何从远程仓库拉取代码到本地?
可以通过git pull
从远程仓库拉取代码到本地。例如,可以使用git pull origin master
从名为origin的远程仓库的master分支拉取最新代码。
38.如何在Git中合并两个分支?
使用“git merge”
命令合并两个分支。例如,要将名为“feature-branch”
的分支合并到当前分支,请输入“git merge feature-branch”
。
39.如何在Git中解决冲突?
使用“git merge”
命令合并分支时可能会发生冲突。要解决冲突,请手动编辑包含冲突的文件,然后使用“git add”
和“git commit”
命令提交更改。
40.什么是 git flow
Git flow是一种Git分支模型,它为团队提供了一种规范化的开发流程,使得代码库更容易管理、维护和协作。它的核心思想是在代码库中维护两个主要的分支:
一个稳定的主分支(master),用于发布生产版本;另一个是开发分支(develop),用于开发新功能和修复错误。此外,git flow还定义了一些支持分支,如feature、
release、hotfix,它们有助于更好地管理和协作团队成员在不同的开发阶段中的工作。总之,Git flow提供了一种标准化的Git分支模型,使团队能够更
有效地协作和管理Git代码库。
四、CMS项目面试题
41. 什么是Axios拦截器?
Axios拦截器是Axios提供的一种机制,用于在请求和响应发送之前或之后执行某些操作,比如添加请求头、检查请求参数、处理响应数据等。
42.如何使用Axios拦截器?
使用Axios拦截器,需要通过Axios提供的interceptors
属性来创建请求和响应拦截器
// 添加请求拦截器
axios.interceptors.request.use(function (config) {
// 在发送请求之前做些什么
config.headers.Authorization = localStorage.getItem('token')
return config;
}, function (error) {
// 对请求错误做些什么
return Promise.reject(error);
});
// 添加响应拦截器
axios.interceptors.response.use(function (response) {
// 对响应数据做点什么
return response;
}, function (error) {
// 对响应错误做点什么
return Promise.reject(error);
});
43.如何在Axios拦截器中处理错误?
在Axios拦截器中处理错误,需要在拦截器的两个回调函数中来处理
- 第一个回调函数用来处理 业务状态码的错误
- 第二个回调函数用来处理 HTTP响应状态码的错误
44.简述前端JWT的作用及原理,并说明其优缺点。
JWT(JSON Web Token)是一种用于在网络应用中传递信息的安全方式。JWT实际上是一段加密的JSON数据,由三部分组成:头部(Header)、载荷(Payload)和签名(Signature)。
作用:
- 身份认证:JWT可以在用户登录后生成一个JWT,用于后续的身份认证,无需在每个请求中都携带身份信息。
- 授权:JWT中可以携带用户的授权信息,使得服务器端可以根据授权信息进行相应的操作,从而实现授权。
- 信息交换:JWT可以在不同的系统之间传递信息,比如OAuth2中的AccessToken。
优点:
- 无状态:JWT是一种无状态的认证方式,即服务器端不需要保存任何用户信息,使得应用可以更容易地扩展。
- 安全性高:由于JWT采用了加密算法,能够保证传输过程中的数据不被篡改和窃取。
- 跨平台:由于JWT是一种标准化的认证方式,因此可以在不同的平台上使用。
缺点:
- 信息冗余:由于JWT中包含了头部、载荷和签名三部分信息,因此可能会导致信息冗余。
- 容易被篡改:如果签名算法不够安全,就有可能被恶意攻击者篡改JWT中的信息。
- 无法撤销:由于JWT一旦颁发,就无法撤销,因此如果JWT泄露,就可能导致严重的安全问题。
45.前端web登录流程
前端web登录流程通常涉及以下几个步骤:
- 用户输入用户名和密码,并点击“登录”按钮。
- 前端代码将用户输入的用户名和密码发送到后端服务器。
- 后端服务器接收到前端发送的用户名和密码,并进行身份验证。通常,后端服务器会将用户名和密码与存储在数据库中的用户凭据进行比对,以验证用户身份。
- 如果后端服务器验证成功,则会向前端发送一个带有用户信息的令牌(通常是 JSON Web Token)。如果验证失败,则会向前端发送一个错误消息。
- 前端代码接收到令牌,并将其存储在浏览器的本地存储中(例如,使用localStorage或sessionStorage)。
- 以后,当用户进行需要身份验证的操作时,前端代码将令牌发送到后端服务器以验证用户身份。如果令牌有效,则后端服务器允许该操作。否则,后端服务器将返回一个错误消息。
总之,前端web登录流程可以归纳为:用户输入凭据 -> 前端发送凭据到后端 -> 后端验证凭据并发送令牌 -> 前端存储令牌并发送到后端以进行身份验证。
46.什么是iframe标签?
iframe标签是HTML中的一个标签,它允许将一个HTML文档嵌入到另一个HTML文档中。它可以用于在一个HTML页面中嵌入
其他网站或自己的HTML页面。iframe标签通过src属性指定要嵌入的HTML文档的URL。
47.iframe标签的缺点是什么?
iframe标签的主要缺点是它可能导致性能问题。由于iframe标签需要加载另一个HTML文档,因此它可能导致页面加载速度变
慢。另外,由于iframe标签可以显示其他网站的内容,因此它也可能导致安全问题。
48.XSS
XSS (Cross-Site Scripting),跨站脚本攻击
XSS(Cross-Site Scripting,跨站脚本攻击)是一种常见的网络安全漏洞,攻击者会利用该漏洞将恶意代码注入到一个网站的
页面中,然后当用户访问该页面时,恶意代码就会执行,攻击者就可以利用这种方式来窃取用户的敏感信息或者劫持用户的会
话。
这种攻击方式通常利用网站未过滤或过滤不严格的用户输入数据,比如输入框、URL参数等,攻击者会在这些数据中嵌入恶意
的脚本代码,当用户在网站上执行了这些脚本代码时,就会产生XSS攻击。
例如,攻击者可以在一个论坛的回复框中输入一段恶意的脚本代码,然后当其他用户在查看该回复时,就会执行这段脚本代
码,从而导致攻击者获取用户的Cookie等敏感信息
具体来说,网站可以采用以下几种方式来防止XSS攻击:
- 输入过滤: 网站可以对用户输入的数据进行过滤,比如只允许特定的字符集、限制输入长度等。
- 输出转义:网站可以对输出到页面上的数据进行转义,将特殊字符(如<, >, ", '等)转换成HTML实体,从而防止恶意代码的注入。
- 使用CSP(Content Security Policy):CSP是一种安全策略,它允许网站开发者指定哪些内容是可信的,哪些是不可信的,从而防止恶意代码的注入。
- 使用HTTP-only Cookie:HTTP-only Cookie是一种Cookie属性,它可以防止JavaScript脚本读取或修改Cookie内容,从而防止攻击者利用XSS攻击来盗取用户的Cookie。
总之,要防止XSS攻击,网站开发者需要充分了解XSS攻击的原理,并采取一系列的措施来确保网站的安全性
49.CSRF
CSRF(Cross Site Request Forgery),跨站请求伪造
跨站请求伪造(Cross-Site Request Forgery,CSRF)是一种网络攻击方式,它通常会利用用户已经登录过的身份,来执行一
些恶意操作,比如删除账户、购买商品等。
攻击者会在一个恶意网站中构造一个请求,然后引诱用户在已登录的另一个网站上点击一个链接,这个链接会让用户在不知情
的情况下发送请求到目标网站,这时候目标网站会认为这个请求是合法的,因为它携带了用户已经登录的身份信息,从而执行
攻击者想要的操作。
例如,一个攻击者可以在一个恶意网站中构造一个请求,这个请求可以让用户在另一个网站上删除自己的账户,然后攻击者就
会通过这种方式来盗取用户的账户。
为了防止CSRF攻击,网站通常会采取一些防范措施,比如添加随机令牌、验证Referer头、验证请求的来源地址等。
50.ajax、axios、fetch的区别
(1)AJAX
Ajax 即“AsynchronousJavascriptAndXML”
(异步 JavaScript 和 XML),是指一种创建交互式网页应用的开发技术。它是
一种在无需重新加载整个网页的情况下,能够更新部分网页的技术。通过在后台与服务器进行少量数据交换,Ajax 可以使网页
实现异步更新。传统的网页(不使用 Ajax)如果需要更新内容,必须重载整个网页页面。其缺点如下:
- 本身是针对MVC编程,不符合前端MVVM的浪潮
- 基于原生XHR开发,XHR本身的架构不清晰
- 不符合关注分离(Separation of Concerns)的原则
- 配置和调用方式非常混乱,而且基于事件的异步模型不友好。
(2)Fetch
fetch号称是AJAX的替代品,是在ES6出现的,使用了ES6中的promise对象。Fetch是基于promise设计的。Fetch的代码结构比起ajax简单多。fetch不是ajax的进一步封装,而是原生js,没有使用XMLHttpRequest对象。
fetch的优点:
- 语法简洁,更加语义化
- 基于标准 Promise 实现,支持 async/await
- 更加底层,提供的API丰富(request, response)
- 脱离了XHR,是ES规范里新的实现方式
fetch的缺点:
- fetch只对网络请求报错,对400,500都当做成功的请求,服务器返回 400,500 错误码时并不会 reject,只有网络错误这些导致请求不能完成时,fetch 才会被 reject。
- fetch默认不会带cookie,需要添加配置项: fetch(url, {credentials: ‘include’})
- fetch不支持abort,不支持超时控制,使用setTimeout及Promise.reject的实现的超时控制并不能阻止请求过程继续在后台运行,造成了流量的浪费
- fetch没有办法原生监测请求的进度,而XHR可以
(3)Axios
- Axios 是一种基于Promise封装的HTTP客户端,其特点如下:
- 浏览器端发起XMLHttpRequests请求
- node端发起http请求
- 支持Promise API
- 监听请求和返回
- 对请求和返回进行转化
- 取消请求
- 自动转换json数据
- 客户端支持抵御XSRF攻击
五、nodejs面试题
51.Node.js是什么?它的主要用途是什么?
Node.js是一个基于Chrome V8引擎的JavaScript运行时环境,它允许JavaScript在服务器端运行。Node.js的主要用途是编写服
务器端应用程序,但它也可以用于编写命令行工具、网络工具和桌面应用程序等。
52.Node.js中的包管理器是什么?它有什么作用?
Node.js中的包管理器是npm
(Node Package Manager
)。它是一个用于安装、管理和分享Node.js模块的工具。npm
允许你
通过命令行安装、卸载和更新模块,还可以搜索和分享你的模块。npm
还可以自动解决依赖关系,并在安装时将所有需要的模
块下载到本地。它们可以提高数据处理的效率和安全性。
53.Node.js中的缓冲区是什么?它们的作用是什么?
答:缓冲区是Node.js中用于处理二进制数据的机制。缓冲区是一个固定大小的内存块,它可以存储任意类型的数据,包括
ASCII、UTF-8和16进制等。缓冲区可以用于处理文件、网络数据和其他I/O操作,它们可以提高数据处理的效率和安全性。
54.如何处理 Node.js 中的异步操作?
在 Node.js 中,异步操作通常通过回调函数来处理。当一个异步操作完成后,会调用回调函数,并将操作结果传递给回调函
数。开发人员可以在回调函数中处理异步操作的结果,例如输出结果、更新数据等。除了回调函数,Node.js
还提供了
Promise
、Async/Await
等方式来处理异步操作
55.什么是模块?如何创建和使用模块?
我们分为三大模块,分别是核心模块、自定义模块和第三方模块。
模块是指一个包含代码的文件或者文件夹。每个模块都拥有自己的作用域,可以通过 require
函数来加载模
块,并使用模块中的代码。可以通过 exports
或 module.exports
对象来向外暴露模块中的内容,其他模块可以通过 require
函
数来引用模块中的内容。
56.什么是webpack(必会)
webpack
是一个打包模块化 javascript
的工具,在webpack里一切文件皆模块,通过loader
转换文件,通过plugin
注入钩子,最后输出由多个模块组合成的文件,webpack
专注构建模块化项目
57.Webpack的优点是什么?(必会)
- 专注于处理模块化的项目,能做到开箱即用,一步到位
- 通过plugin扩展,完整好用又不失灵活
- 通过loaders扩展, 可以让webpack把所有类型的文件都解析打包
- 社区区庞大活跃,经常引入紧跟时代发展的新特性,能为大多数场景找到已有的开源扩展
58.webpack的构建流程是什么?从读取配置到输出文件这个过程尽量说全(必会)
Webpack 的运行流程是一个串行的过程,从启动到结束会依次执行以下流程:
1. 初始化参数:从配置文件读取与合并参数,得出最终的参数
2. 开始编译:用上一步得到的参数初始化 Compiler 对象,加载所有配置的插件,开始执行编译
3. 确定入口:根据配置中的 entry 找出所有的入口文件
4. 编译模块:从入口文件出发,调用所有配置的 Loader 对模块进行翻译,再找出该模块依赖的模块,再递归本步骤直到所有入口依赖的文件都经过了本步骤的处理
5. 完成模块编译:在经过第4步使用 Loader 翻译完所有模块后,得到了每个模块被翻译后的最终内容以及它们之间的依赖关系
6. 输出资源:根据入口和模块之间的依赖关系,组装成一个个包含多个模块的 Chunk,再把每个 Chunk 转换成一个单独的文件加入到输出列表,这步是可以修改输出内容的最后机会
7. 输出完成:在确定好输出内容后,根据配置确定输出的路径和文件名,把文件内容写入到文件系统。
在以上过程中,Webpack 会在特定的时间点广播出特定的事件,插件在监听到感兴趣的事件后会执行特定的逻辑,并且插件可以调用 Webpack 提供的 API 改变 Webpack 的运行结果
59.说一下 Webpack 的热更新原理(必会)
webpack 的热更新又称热替换(Hot Module Replacement),缩写为 HMR。这个机制可以做到不用刷新浏览器而将新变更的模块替换掉旧的模块。
HMR的核心就是客户端从服务端拉去更新后的文件,准确的说是 chunk diff (chunk 需要更新的部分),实际上 WDS 与浏览器之间维护了一个 Websocket,当本地资源发生变化时,WDS 会向浏览器推送更新,并带上构建时的 hash,让客户端与上一次资源进行对比。客户端对比出差异后会向 WDS 发起 Ajax 请求来获取更改内容(文件列表、hash),这样客户端就可以再借助这些信息继续向 WDS 发起 jsonp 请求获取该chunk的增量更新。
后续的部分(拿到增量更新之后如何处理?哪些状态该保留?哪些又需要更新?)由 HotModulePlugin 来完成,提供了相关 API 以供开发者针对自身场景进行处理,像react-hot-loader 和 vue-loader 都是借助这些 API 实现 HMR。
60.webpack与grunt、gulp的不同?(必会)
1) 三者之间的区别
三者都是前端构建工具,grunt和gulp在早期比较流行,现在webpack相对来说比较主流,不过一些轻量化的任务还是会用gulp来处理,比如单独打包CSS文件等。
grunt和gulp是基于任务和流(Task、Stream)的。类似jQuery,找到一个(或一类)文件,对其做一系列链式操作,更新流上的数据, 整条链式操作构成了一个任务,多个任务就构成了整个web的构建流程。
webpack是基于入口的。webpack会自动地递归解析入口所需要加载的所有资源文件,然后用不同的Loader来处理不同的文件,用Plugin来扩展webpack功能。
2) 从构建思路来说
gulp和grunt需要开发者将整个前端构建过程拆分成多个Task
,并合理控制所有Task
的调用关系 webpack需要开发者找到入口,并需要清楚对于不同的资源应该使用什么Loader做何种解析和加工
3) 对于知识背景来说
gulp更像后端开发者的思路,需要对于整个流程了如指掌 webpack更倾向于前端开发者的思路
61.有哪些常见的Loader?他们是解决什么问题的?(必会)
1、 file-loader:把文件输出到一个文件夹中,在代码中通过相对 URL 去引用输出的文件
2、 url-loader:和 file-loader 类似,但是能在文件很小的情况下以 base64 的方式把文件内容注入到代码中去
3、 source-map-loader:加载额外的 Source Map 文件,以方便断点调试
4、 image-loader:加载并且压缩图片文件
5、 babel-loader:把 ES6 转换成 ES5
6、 css-loader:加载 CSS,支持模块化、压缩、文件导入等特性
7、 style-loader:把 CSS 代码注入到 JavaScript 中,通过 DOM 操作去加载 CSS。
8、 eslint-loader:通过 ESLint 检查 JavaScript 代码
62.Loader和Plugin的不同?(必会)
1) 不同的作用
Loader直译为"加载器"。Webpack将一切文件视为模块,但是webpack原生是只能解析js文件,如果想将其他文件也打包的话,就会用到loader。 所以Loader的作用是让webpack拥有了加载和解析非JavaScript文件的能力。
Plugin直译为"插件"。Plugin可以扩展webpack的功能,让webpack具有更多的灵活性。 在 Webpack 运行的生命周期中会广播出许多事件,Plugin 可以监听这些事件,在合适的时机通过 Webpack 提供的 API 改变输出结果。
2) 不同的用法
Loader在module.rules中配置,也就是说他作为模块的解析规则而存在。 类型为数组,每一项都是一个Object,里面描述了对于什么类型的文件(test),使用什么加载(loader)和使用的参数(options)
Plugin在plugins中单独配置。 类型为数组,每一项是一个plugin的实例,参数都通过构造函数传入。
63.重绘和回流(重排)
1. 回流(重排)
当 Render Tree
(渲染树)中部分或者全部元素的布局,尺寸大小,结构等发生改变时,浏览器就会重新渲染部分或全部文档的过程称为 回流。
2. 重绘
页面中元素的颜色,字体,或其他外观属性改变时,浏览器需要重绘来更新外观(比如:color、background-color、outline
等), 称为重绘。
重绘不一定引起回流(重排),而回流(重排)一定会引起重绘。
3. 会导致回流(重排)的操作:
1.1 页面的首次刷新
1.2 浏览器的窗口大小发生改变
1.3 元素的大小或位置发生改变
1.4 改变字体的大小
1.5 内容的变化(如:input
框的输入,图片的大小)
1.6激活css
伪类 (如::hover
)
1.7 脚本操作DOM
(添加或者删除可见的DOM
元素)
1.8 简单理解影响到布局了,就会有回流
64.什么是跨域?
跨域:指的是浏览器不能执行其他网站的脚本。它是由浏览器的同源策略造成的,是浏览器对 javascript 施加的安全限制。
通俗的说就是协议 端口 主机 三者 不一致就会造成跨域
解决方案:
- 使用代理服务器:可以在本地搭建一个代理服务器,通过代理服务器转发请求,从而解决跨域问题。
- 使用 JSONP:JSONP 是一种跨域数据传输方式,可以通过动态插入 script 标签的方式实现跨域访问,JSONP是比较老的一种方案,只支持get请求,不支持post请求
- 使用 CORS:CORS 是一种跨域资源共享的方式,可以通过在服务器端配置 HTTP 头信息,让浏览器允许跨域访问。 它通过服务器增加一个特殊的
Header[Access-Control-Allow-Origin]
来告诉客户端跨域的限制 - 使用 WebSocket:WebSocket 是一种基于 TCP 的协议,可以实现双向通信,不存在跨域的限制。
六、vue面试题
65.什么是MVVM
MVVM
,是Model-View-ViewModel
的简写,是M
-V
-VM
三部分组成。它本质上就是MVC
的改进版。
Model
(模型) : 表示应用程序中的数据模型,它代表着应用程序中的业务逻辑和状态。
View
(视图): 表示应用程序中的用户界面。
ViewModel
(视图模型) : 是一个桥梁,将模型和视图连接在一起,它提供了视图所需的数据和命令,并将用户的输入转换为模型的操作。
**MVVM
采用双向数据绑定,view
中数据变化将自动反映到viewmodel
上,反之,model
中数据变化也将会自动展示在页面上。**把Model
和View
关联起来的就是ViewModel
。ViewModel负责把Model的数据同步到View显示出来,还负责把View的修改同步回Model。
MVVM
核心思想,是关注model
的变化,让MVVM
框架利用自己的机制自动更新DOM
,也就是所谓的数据-视图分离,数据不会影响视图。
MVVM
就是将其中的View
的状态和行为抽象化,其中ViewModel
将视图 UI 和业务逻辑分开,它可以取出 Model
的数据同时帮忙处理 View
中由于需要展示内容而涉及的业务逻辑。
66.vue的理解?
Vue.js
是一个渐进式的 JavaScript
框架,旨在通过尽可能简单的 API
实现响应式数据绑定和组合的视图组件。
Vue.js
的核心是数据驱动视图,通过组件内特定的方法实现视图和模型的交互 。
Vue.js
的响应式系统可以在模型数据变化时,视图会自动更新。这意味着,我们可以在不手动操作 DOM
的情况下改变视图。
Vue.js
还提供了许多其他功能,如组件系统、路由、状态管理等,可以帮助你构建复杂的单页应用。
总的来说,Vue.js
是一个轻量级的、易于使用的前端框架,可以帮助你快速构建响应式的 Web
应用。
67.说5个vue的指令
v-bind:
绑定属性v-if
、v-show:
条件渲染v-for:
列表渲染v-model:
双向绑定v-html:
解析html字符串v-on:
绑定事件
68.vue 单页面应用
vue 是一个单页面应用 ,这个vue项目其实只会有一个 index.html 页面,它内容的切换本质都是通过切换div来实现模拟多页面的
SPA单页面应用(SinglePage Web Application
,简称 SPA
),指的是只有一个主页面的应用,一开始只需要加载一次js
、css
等相关资源,所有内容都包含在主页面上,对每一个功能模块组件化,单页面应用跳转,就是切换相关组件,仅仅刷新局部资源。(单页面应用指一个系统只加载一次资源,然后下面的操作交互、数据交互是通过router、ajax来进行,页面并没有刷新)
与传统的多页面应用相比,单页面应用具有许多优势,包括:
- 快速响应:由于不需要重新加载页面,因此 SPA 应用可以快速响应用户的操作。
- 减少服务器负载:由于大部分的处理都是在客户端进行的,因此 SPA 应用可以减少服务器的负载。
- 更好的用户体验:由于 SPA 应用的页面切换非常流畅,因此它可以提供更好的用户体验。
然而,单页面应用也有一些缺点,包括:
- 较难调试:由于
SPA
应用的代码都在客户端运行,因此调试可能会更加困难。 - 首次加载耗时多:解决方法通过路由懒加载: 可以有效的分担首页所承担的加载压力,减少首页加载用时。
SEO
难度较大: 由于所有的内容都在一个页面上动态替换显示,所以在SEO
上其有着天然的弱势。 为了解决这个问题,可以使用服务端渲染(Server-Side Rendering,简称 SSR
)技术,在服务器端渲染SPA
应用的内容,使得爬虫可以正常抓取页面内容。
69.v-for和v-if为什么不能一起使用
在vue2
中v-for
优先级高于v-if
,如果二者在同一级标签里面使用,每次都要先循环,再判断,消耗很多性能。
解决办法的话,可以在外层包装一个div
,使用v-if
做一次判断即可。Vue3
解决了这个问题,将v-if
的优先级调整为高于v-for
了。
70.计算属性与watch的区别
computed
是用来计算出来一个值的,这个值调用的时候不需要加括号,会根据依赖进行缓存,依赖不变,computed
的值不会重新计算。
watch
是来监听的,有2个选项
immediate
:表示是否要在第一次渲染的时候执行这个函数deep
:如果我们监听一个对象,那么我们要看这个对象里面的属性是否变化,如果某个属性变化了,就去执行一个函数
71.vue组件中data为什么必须是一个函数
在 Vue.js 中,组件的 data 选项必须是一个函数
,这是因为每个组件实例都应该有自己的状态,如果 data 不是一个函数,那么所有实例将共享同一个数据对象,这会导致组件之间的状态混乱。
举个例子,假设你有一个组件 A 和组件 B,如果你把 data 写成这样:
data: {
message: 'Hello'
}
那么组件 A 和组件 B 中的 message 都是同一个值,如果在组件 A 中修改了 message,那么组件 B 中的 message 也会改变。这显然不是你想要的结果。
因此,Vue.js 要求 data 选项必须是一个函数,这样每个组件实例都可以有自己的 data 对象。你可以这样写:
data: function () {
return {
message: 'Hello'
}
}
这样就能保证每个组件实例都有自己的 data 对象,组件之间的状态就不会混乱了。
72.nextTick的理解
nextTick 是 Vue.js 中一个用来在下一个事件循环中调用回调函数的方法。( 就是你放在 $ nextTick 当中的操作不会立即执行,而是等数据更新、DOM更新完成之后再执行,这样我们拿到的肯定就是最新的了 )这个方法通常用在等待数据或 DOM 元素更新之后执行一些代码。也可以说在下一次DOM更新结束后执行其指定的回调
这句话扩展开来说,就是由于Vue中DOM更新是「异步执行」的,即修改数据时,视图不会立即更新,而是会监听数据变化,并缓存在同一事件循环中,等同一数据循环中的所有数据变化完成之后,再统一进行视图更新。经常我们会在还未更新的时候就使用了某个元素,这样是拿不到变更后的dom的,所以为了确保能够得到更新后的DOM,所以设置了nextTick()方法。在修改数据之后立即使用这个方法,获取更新后的DOM。简单概括,vue中的nextTick主要用于处理数据动态变化后,DOM还未及时更新的问题,用nextTick可以获取数据更新后最新dom的变化。
73.插槽
在 Vue.js 中,插槽(slot
)是一种机制,可以在父组件的模板中定义一个占位符,然后在子组件中插入内容。这样,子组件就
可以在父组件的模板中渲染内容,使得子组件可以更灵活地与父组件进行交互。
- 插槽的使用过程其实是抽取共性、预留不同;
- 我们会将共同的元素、内容依然在组件内进行封装;
- 同时会将不同的元素使用slot作为占位,让外部决定到底显示什么样的元素;
插槽有两种类型:
- 具名插槽:具名插槽使用特定的名称来标识,子组件可以插入到特定的插槽中。
- 不具名插槽:不具名插槽没有名称,子组件中的内容会插入到不具名插槽中。
74.路由模式
- hash模式:
- 浏览器中符号是“
#
”,#以及#后面的字符称之为hash
,又叫前端路由 - 用
window.location.hash
读取 - hash 虽然在
URL
中,但不会向服务器发送请求 - hash 改变会触发
hashchange
事件, 并根据hash值来修改页面内容 - hash发生变化的
url
都会被浏览器记录下来,从而实现浏览器的前进后退。
- 浏览器中符号是“
- history模式:
- history 采用 了
HTML5
History
API
- history 模式不仅可以在
url
里放参数,还可以将数据存放在一个特定的对象中 - 它也有个问题:不怕前进,不怕后退,就怕刷新(如果服务器中没有相应的响应或资源,会分分钟刷出一个404来),因为刷新是实实在在地去请求服务器的。
- history 采用 了
75.说说vue的生命周期
vue
组件生命周期:从创建 到 销毁 的整个过程就是 – Vue
实例的 生命周期
Vue中的生命周期本质上就是按顺序固定执行一个个的钩子函数,我们开发者可以在每个函数中写入特定代码来实现我们需要的功能例如我们常用的ajax请求通常就放在created或者mounted中。
vue2的生命周期从分类上来看有如下几种情况:
- 组件创建和挂载相关的钩子函数有
beforeCreate
created
beforeMount
mounted
- 组件更新相关的钩子函数有
beforeUpdate
updated
- 组件销毁相关的钩子函数有
beforeDestroy
destroyed
还有一个组件缓存激活相关的钩子函数是:activated和deactivated,这两个要配合keep-alive 缓存的组件一起使用
kee-alive
是 Vue 内置的一个组件,可以使被包含的组件保留状态,或避免重新渲染 。也就是所谓的组件缓存 keep-alive ,当它包裹动态组件时,会缓存不活动的组件实例,而不是销毁它们
vue3总体来说什么周期执行顺序是一样的,不同点在于beforeCreate和created都被setup函数替代了
76.vue旧地复用策略
Vue
会尽可能的就地(同层级,同位置),对比虚拟dom
,复用旧dom
结构,进行差异化更新,vue
采用的是diff算法进行对比。它会先同层级根元素进行比较,如果根元素变化的话,就不考虑复用了,如果根元素没有变化,就会对比同级兄弟元素,默认按照下标进行对比复用,如果设置了key
就会按照相同key
的新旧元素进行对比复用,key
必须是一个唯一不重复的字符串或者数值,key
的好处就是可以提高虚拟DOM
对比的复用性能。
77.深度侦听在什么情况下使用?立即侦听什么情况下使用?
deep
(深度侦听):默认情况下,侦听器无法侦听对象的属性值的变化,如果想实现这个效果,则需要添加deep
配置为true
handler
(固定方法触发):因为你要添加deep
的配置,所以,侦听器的形式要变更为对象形式,只有对象才能添加其它的配置, 同时侦听函数必须为handler
immediate
(立即侦听):如果需要默认一进页面就触发一次,添加immediate
配置选项为true
78.前置路由守卫
全局前置路由守卫: 初始化的时候被调用,每次 路由切换之前 被调用。
路由跳转之前, 会触发的一个函数 叫前置路由守卫
语法:router.beforeEach((to, from, next) => {这里可以写路径的跳转判断/有无token值的情况分析})
作用 : 防止别人猜到网址的hash值后直接跳过登录就可以查看数据
里面的3个参数:
to
: 到哪里去
from
: 从哪里来
next
: 放行函数 next()
:放行 , next(false)
:不放行
79.Vuex核心属性:
- state:定义需要管理的数据
- getters:state派生出来的数据,相当于state的计算属性
- mutation:里面定义的是同步的更新数据方法,每个方法里都有两个参数,一个是
state
,一个是payload
,通过store.commit
调用 - action:里面定义的是异步的方法,每个方法里面有两个参数,一个是
store
,一个是payload
,通过store.dispatch
调用,在actions
里也可以提交mutation
,通过store.commit
- module:将
vuex
模块化,可以让每一个模块拥有自己的state
、mutation
、action
、getters
,结构清晰,方便管理
80.Vue2优点和缺点讲解
优点
- 轻量级的框架
- 双向数据绑定
- 组件化开发
- 单页面路由
- 学习成本低
- 虚拟dom
- 渐进式框架
- 数据和结构的分离
- 运行速度快
- 插件化
缺点
- 不支持IE8以下
- 社区可能没有Angular和React那么丰富
- Vue 不缺入门教程,可是很缺乏高阶教程与文档。同样的还有书籍
- 因为是单页面应用,不利于seo优化
- 初次加载时耗时多
81.在使用vuex时怎么实现数据的持久化
我们通常是将数据保存到本地存储中,当重新刷新页面后再从本地存储中将之前的数据加载回来
保存到vuex
中的state
中。这样就能实现vuex
的数据持久化了
82.三次握手和四次挥手
三次握手是用于在俩台计算机之间建立网络连接
, 确认双方的接收与发送能力是否正常 ,它包括三个步骤:
1.客户端向服务端发送连接请求
2.服务端向客户端发送确认消息,表明服务器已准备好接受连接
3.客户端向服务器发送确认消息,表明客户端已收到服务端的确认消息,并准备好开始数据传输
四次挥手是用于在俩台计算机之间终止网络连接
,它包括以下四个步骤:
1.客户端向服务器发送断开连接请求
2.服务器向客户端发送确认消息,表明服务器已收到断开连接的请求。(服务端收到关闭请求的时候可能这个时候数据还没发送完,所以服务端会先回复一个确认报文,表示自己知道客户端想要关闭连接了,但需要等待数据传输完)
3.服务器向客户端发送断开连接的请求。(会主动发送FIN报文,告知客户端,服务端准备关闭连接了)
4.客户端向服务器发送确认消息,表明客户端已收到服务器的断开连接请求,稍后进行断开
扩展、 挥手为什么需要四次?
因为当服务端收到客户端的SYN连接请求报文后,可以直接发送SYN+ACK报文。其中ACK报文是用来应答的,SYN报文是用来同步的。但是关闭连接时,当服务端收到FIN报文时,很可能并不会立即关闭SOCKET,所以只能先回复一个ACK报文,告诉客户端,“你发的FIN报文我收到了”。只有等到我服务端所有的报文都发送完了,我才能发送FIN报文,因此不能一起发送。故需要四次挥手。
补充、TCP和UDP的区别
TCP
和UDP
都是传输层协议
TCP
是一种面向有连接的传输层协议,能够对自己提供的连接实施控制。适用于要求可靠传输的应用,例如文件传输。面向字节流,传输慢 。
UDP
是一种面向无连接的传输层协议,不会对自己提供的连接实施控制。适用于实时应用,例如:IP电话、视频会议、直播等。,以报文的方式传输,效率高 。
UDP | TCP | |
---|---|---|
是否连接 | 无连接 | 面向连接 |
是否可靠 | 不可靠传输,不使用流量控制和拥塞控制 | 可靠传输,使用流量控制和拥塞控制 |
连接对象个数 | 一对一,一对多,多对一,多对多 | 只能有俩个端点,一对一通信 |
传输方式 | 面向报文 | 面向字节流 |
首部开销 | 开销小,仅8字节 | 最小20字节,最大60字节 |
83.一个页面从输入 URL 到页面加载显示完成的过程
1、URL解析:地址栏输入地址,浏览器对输入内容进行解析,判断URL的合法性,和是否有可用缓存
2、DNS解析:域名解析系统(DNS)查找对应的IP地址
3、建立TCP连接(三次握手):浏览器向服务器发起TCP连接,与浏览器建立TCP三次握手
4、HTTP请求:浏览器将http请求数据发给服务器(客户端–>服务器)
5、HTTP响应:服务器处理收到的请求,返回响应结果至浏览器(服务器–>客户端)
6、关闭TCP连接(四次挥手):数据传输完成后,还要经过四次握手以终止连接
7、页面渲染:浏览器解析响应结果,进行页面渲染
84.vue双向数据绑定原理
比如说,当在输入框输入文字时,vue会检测到数据的变化,然后更新对应的视图。同样,如果你通过代码修改了数据,那么vue
也会自动更新视图,其原理是通过数据劫持和发布订阅模式实现的。
首先,Vue
通过Object.defineProperty( )
方法对数据进行劫持,监听数据的变化,并通过getter
和setter
方法对数据进行读写。
其次,Vue通过发布订阅模式,维护了一个订阅者数组,当数据发生变化时,Vue
会通知所有订阅者进行更新。因此,当用户在页面上进行修改时,Vue
也会自动更新对应的数据,并通知所有订阅者更新视图,同时当数据发生变化时,Vue也会更新对应的视图,通过这样的机制,Vue实现了双向数据绑定,使得数据和视图的变化可以互相影响
补充:订阅者是Vue中的一个概念,它是一个用于管理更新视图的对象,当数据发生变化时,Vue会通知所有的订阅者进行更新,在Vue中,每一个挂载到视图上的组件,或者每一个watcher,都可以被看成一个订阅者,他们订阅了某一个数据的变化,并等待数据发生变化时进行更新,订阅者是Vue实现双向数据绑定的关键组成部分,管理着数据和视图之间的关系,保证了数据的变化能够及时反应到视图上
vue双向数据绑定原理
是数据劫持加观察者模式实现的。 大致分成了以下两步:
- 通过 Object.defineProperty 劫持数据,收集依赖
- 当数据被访问或更新时,通知对应依赖去响应视图的变化 当 Vue 实例被创建时,它会在内部遍历所有数据并使用 Object.defineProperty() 函数为每个属性添加 getter 和 setter。这样,当数据被访问(get)或修改(set)时,Vue 就可以捕获数据并通知观察者(渲染页面)。
补充. 双向数据绑定原理之Vue3.0比vue2.0的优势有哪些?
vue2.0使用了 Object.defineProperty
的方法,首先它是无法检测到对象属性的新增或者删除,其次无法监听数组的变化,vue在实现数组的响应式时,它使用了一些hack
, 把无法监听数组的情况通过重写数组的部分方法来实现响应式,这也只限制在数组的push/pop/shift/unshift/splice/sort/reverse
七个方法, 其他数组方法及数组的使用则无法检测到 。
vue3.0 使用了proxy
来代替Object.defineProperty
, proxy
属性是ES6中新增的一个属性, proxy
属性也是一个构造函数,他也可以通过new的方式创建这个函数, proxy直接代理的是整个对象而非对象属性,proxy的代理针对的是整个对象而不是像object.defineProperty
针对某个属性, 只需要做一层代理就可以监听同级结构下的所有属性变化,。
85.页面优化:
- v-if和v-for不能连用
- 更多的情况下,使用v-if代替v-show
- 要保证key值的唯一
- 使用组件懒加载或者图片懒加载
- 防抖和节流的使用
- 模块按需导入
- 打包优化
- 使用cdn加载第三方模块
- 缓存常用信息
- 精灵图,base64
补充. v-if 和 v- show的区别
作用:都是可以实现元素的显示与隐藏
v-show
频繁切换标签,用v-show
css手段控制标签显示隐藏v-if
不频繁切换标签,用v-if,创建删除标签显示隐藏,惰性的,一开始为false的,不会创建标签,性能更好
补充、v-model的实现原理
在 Vue.js
中,v-model
指令是一种语法糖,它的作用是为表单元素绑定双向数据绑定。v-model
指令的实现原理是基于计算属性和事件绑定。它会将表单元素的 value
属性绑定到一个计算属性上,并且在计算属性的 setter
中触发 input
事件来更新 Vue 实例中的数据。
补充、vue2中的filter过滤器
vue2
有使用过滤器 vue3
已舍弃使用
vue2
过滤器的使用:用于一些常见的文本格式化 例如:日期格式化、数字大小写、单位转换、文本格式化等
过滤器的作用:可以在不改变原数据 只是对数据进行加工处理并返回过滤后的数据,再进行调用处理
过滤器分为全局过滤器和局部过滤器
过滤器只能应用在两个地方:双花括号插值
和v-bind
表达式(后者从 2.1.0+ 开始支持)。例如
<!--在双花括号中使用 格式:{{值 | 过滤器的名称}}-->
<div>{{3 | addZero}}</div>
<!--在v-bind中使用 格式:v-bind:id="值 | 过滤器的名称"-->
<div v-bind:id="1 | addZero">11</div>