变量 产生作用的区域就叫做作用域
全局作用域
局部作用域
函数作用域
块级作用域
作用域链的本质是变量查找机制
a. 会优先查找自己的作用域
b. 自己的作用域查找不到的话会往上查找父级直到全局作用域
是 JS
中一种自动回收或释放内存的机制 简称 GC
引用计数法:IE采用的引用计数算法, 定义“内存不再使用
”的标准很简单,就是看一个对象是否有指向它的引用
如果这个值的被引用了一次,那么就记录次数1 , 如果减少一个引用就减1。 如果引用次数是0 ,则释放内存。但它却存在一个致命的问题:嵌套引用。
标记清除法:就是从根部
(在JS中就是全局对象)出发定时扫描内存中的对象。 凡是能从根部到达的对象,都是还需要使用的。
无法由根部出发触及到的对象被标记为不再使用,稍后进 行回收
就是有权访问另一个函数作用域中变量的函数
在一个函数内部创建另外一个函数
封闭数据,实现数据私有,防止数据被意外修改
容易导致内存泄露
使用 var
声明的变量,会被提升到函数或全局作用域的顶部,这个现象叫做变量提升。
var
会存在变量提升,let/const
声明的变量不存在变量提升
是一种特殊的函数,主要用来初始化对象 ,同时可以用构造函数来快速创建多个类似的对象。
1.Array.from
2.Array.prototype.slice.call( )
3…展开运算符
在 JavaScript
中,基本类型是没有属性和方法的,但是为了便于操作基本类型的值,在调用基本类型的属性或方法时 JavaScript
会在后台地将基本类型的值转换为对象,这些对象就是包装类型
JavaScript
共有八种数据类型,分别是 Undefined、Null、Boolean、Number、String、Object、Symbol、BigInt
。
其中 Symbol
和 BigInt
是 ES6 中新增的数据类型
Symbol
代表创建后独一无二且不可变的数据类型,它主要是为了解决可能出现的全局变量冲突的问题。
BigInt
是一种数字类型的数据,它可以表示任意精度格式的整数,使用 BigInt
可以安全地存储和操作大整数,即使这个数已经超出了 Number 能够表示的安全整数范围。
这些数据可以分为原始数据类型和引用数据类型:
栈:原始数据类型(Undefined、Null、Boolean、Number、String、Symbol 、BigInt
)
堆:引用数据类型(对象、数组和函数)
重点在于判断 是不是NaN,而不是 数字
isNaN
接收参数后,会尝试将这个参数转换为数值,任何不能被转换为数值的的值都会返回 true
,因此非数字值传入也会返回 true
,会影响 NaN
的判断。Number.isNaN
只会判断 传入的数据 是不是 一个 NaN
,并且不会帮你做类型转换。原型,也叫原型对象,构造函数的一个属性,名字是 prototype
,它本身也是一个对象类型。在构造函数的原型所添加的成员可以被实例所共享。
原型链,指的基于原型继承的那些对象中,它们是通过 原型 prototype
将彼此联系在一起的,这个关系就叫做原型链。
① 当访问一个对象的属性(包括方法)时,首先查找这个对象自身有没有该属性。
② 如果没有就查找它的原型(也就是 proto
指向的 prototype
原型对象)
③ 如果还没有就查找原型对象的原型(Object的原型对象)
④ 依此类推一直找到 Object
为止(null)
⑤ proto
对象原型的意义就在于为对象成员查找机制提供一个方向,或者说一条路线
函数内部自己调用自己, 这个函数就是递归函数,往往都需要添加终止递归的条件。
浅拷贝只是针对引用类型数据中的属性做了一层复制,如果被拷贝的属性也是引用类型,那么这个属性只是复制了这个引用地址。
做了浅拷贝的对象之间可能会相互影响
深拷贝是针对引用类型数据中的属性做无限层级的复制,不管属性是值类型还是引用类型,会完整复制一份。 其在堆内存中完全开辟了一块内存地址,并将原有的对象完全复制过来存放
做了深拷贝的两个对象之间相互不会影响
除了 递归克隆对象、JSON.stringify
两种方式做的拷贝,其他方法全部都是浅拷贝
this
指向,call、apply
在修改 this 指向的同时也会调用原函数、bind
只会返回修改 this 指向后的函数call
和 apply
接收参数的方式不一样,call
类似普通函数一样接收参数、apply
接收的参数必须都放在一个数组内。成功(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 版本 |
事件流:又称为事件传播,是页面中接收事件的顺序。DOM2级事件规定的事件流包括了3个阶段:
事件捕获(Event Capturing)
事件开始由较为不具体的节点接收后,然后开始逐级向下传播到最具体的元素上。
事件捕获的最大作用在于:事件在到达预定⽬标之前就可以捕获到它。
如果仍以上面那段 HTML 代码为例,当点击按钮后,在事件捕获的过程中,document 对象会首先接收到这个 click
事件,然后再沿着 DOM 树依次向下,直到 。具体顺序如下:
事件冒泡(Event Bubbling)
事件开始由最具体的元素(⽂档中嵌套层次最深的那个节点)接收到后,开始逐级向上传播到较为不具体的节点。
<html>
<head>
<title>Documenttitle>
head>
<body>
<button>按钮button>
body>
html>
如果点击了上面页面代码中的 按钮,那么该
click
点击事件会沿着 DOM 树向上逐级传播,在途经的每个节点上都会发生,具体顺序如下:
事件委托: 利用了事件冒泡的机制,在较上层位置的元素上添加一个事件监听函数,来管理该元素及其所有子孙元素上的某一类的所有事件。
示例
<ul id="list">
<li>111li>
<li>222li>
<li>333li>
<li>444li>
<li>555li>
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>
适用场景:在绑定大量事件的时候,可以选择事件委托
优点
主要有以下三种:
application/x-www-form-urlencoded
: 原生的 form 表单提交数据,数据会进行编码,较少使用multipart/form-data
:可以上传键值对,也可以上传文件application/json
:以 JSON 字符串的格式传递,效率较高,经常使用问:如何设置这三种数据类型?
encodeURIComponent()
new FormData()
JSON.stringify()
FormData 是一个以 key/value 形式存储数据的对象,可以实现表单数据的序列化,包括普通的字符串、文件等,主要通过 Ajax 发送表单数据,可以进行二进制的文件进行上传文件
new FormData()
:创建一个新的 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 对象当我们在构造 Promise 的时候,构造函数内部的代码是立即执行的:
Promise.prototype.then()
:为 Promise 实例添加状态改变时的回调函数
Promise.prototype.catch()
:用于指定发生错误时的回调函数
.then(undefined, fn)
一样Promise.all()
: 获取所有的成功结果,或最先失败的结果
Promise.race()
: 获取最快的一个 promise 结果, 不论成功或失败
链式调用:在调用对象上的某个方法之后,还可以接着调用其他方法,如 [1,2,3].map().filter().concat()
、axios({}).then().catch()
原因:方法的返回值是一个对象,对象上拥有某些方法,所以可以接着一直调用
Promise
对象的原型上有 then()
方法,可以被调用then()
方法的返回值是一个新的 Promise
对象 ,状态是 pendingPromise
最终可形成.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()
setTimeout(() => {}, 1000)
、ele.addEventListener('click', () => {})
promise.then(() => {...})
async
声明的异步函数,它的返回值会自动包装为promise
async
声明的异步函数中可以使用await
来调用其他异步函数await
,它会等待promise
执行出结果后将结果返回,可以通过变量接收结果async function () { await asyncFn() }
JavaScript 在设计之初便是单线程,即指程序运行时,只有一个线程存在,同一时间只能做一件事,为了解决单线程运行阻塞问题,JavaScript 用到了计算机系统的一种运行机制,这种机制就叫做事件循环(Event Loop)
如果 JS 设置为多线程,一个线程进行了删除 DOM ,另一个添加 DOM,会导致很多数据和页面更新的问题
在 JavaScript 中,所有的任务都可以分为:
微任务和宏任务在浏览器的执行顺序:
微任务和宏任务的调度机制也被称作为事件循环机制 EventLoop
在代码执行的过程中,同步任务会立即执行,异步任务会通过一些手段和过程才会拿到结果。所以在异步任务等待结果的同时,可先执行其后的同步任务。当异步任务有结果的时候,在回过头来执行异步任务
EvnentLoop执行的机制就是先执行同步代码,接着是微任务,然后是宏任务。
Git 和其他版本代码管理控制系统( 如 SVN 和 CVS )之间的主要区别在于它们的架构和工作方式。Git 是一个分布式版本控制系统,每个开发人员都可以拥有一个完整的代码库副本,并在需要时进行合并更改。
而 SVN 和 CVS 等传统的版本控制系统是基于中央服务器的,每个开发人员都从中央服务器检出代码,然后提交更改
Git的三个区域是工作区、暂存区和本地仓库。可以通过git add
将代码从工作区移动到暂存区,通过git commit
将代码从暂存区移动到本地仓库
可以通过git push
将本地的代码推送到远程仓库。例如,可以使用git push origin master
将本地的master分支推送到名为origin的远程仓库。
可以通过git pull
从远程仓库拉取代码到本地。例如,可以使用git pull origin master
从名为origin的远程仓库的master分支拉取最新代码。
使用“git merge”
命令合并两个分支。例如,要将名为“feature-branch”
的分支合并到当前分支,请输入“git merge feature-branch”
。
使用“git merge”
命令合并分支时可能会发生冲突。要解决冲突,请手动编辑包含冲突的文件,然后使用“git add”
和“git commit”
命令提交更改。
Git flow是一种Git分支模型,它为团队提供了一种规范化的开发流程,使得代码库更容易管理、维护和协作。它的核心思想是在代码库中维护两个主要的分支:
一个稳定的主分支(master),用于发布生产版本;另一个是开发分支(develop),用于开发新功能和修复错误。此外,git flow还定义了一些支持分支,如feature、
release、hotfix,它们有助于更好地管理和协作团队成员在不同的开发阶段中的工作。总之,Git flow提供了一种标准化的Git分支模型,使团队能够更
有效地协作和管理Git代码库。
Axios拦截器是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);
});
在Axios拦截器中处理错误,需要在拦截器的两个回调函数中来处理
JWT(JSON Web Token)是一种用于在网络应用中传递信息的安全方式。JWT实际上是一段加密的JSON数据,由三部分组成:头部(Header)、载荷(Payload)和签名(Signature)。
前端web登录流程通常涉及以下几个步骤:
总之,前端web登录流程可以归纳为:用户输入凭据 -> 前端发送凭据到后端 -> 后端验证凭据并发送令牌 -> 前端存储令牌并发送到后端以进行身份验证。
iframe标签是HTML中的一个标签,它允许将一个HTML文档嵌入到另一个HTML文档中。它可以用于在一个HTML页面中嵌入
其他网站或自己的HTML页面。iframe标签通过src属性指定要嵌入的HTML文档的URL。
iframe标签的主要缺点是它可能导致性能问题。由于iframe标签需要加载另一个HTML文档,因此它可能导致页面加载速度变
慢。另外,由于iframe标签可以显示其他网站的内容,因此它也可能导致安全问题。
XSS (Cross-Site Scripting),跨站脚本攻击
XSS(Cross-Site Scripting,跨站脚本攻击)是一种常见的网络安全漏洞,攻击者会利用该漏洞将恶意代码注入到一个网站的
页面中,然后当用户访问该页面时,恶意代码就会执行,攻击者就可以利用这种方式来窃取用户的敏感信息或者劫持用户的会
话。
这种攻击方式通常利用网站未过滤或过滤不严格的用户输入数据,比如输入框、URL参数等,攻击者会在这些数据中嵌入恶意
的脚本代码,当用户在网站上执行了这些脚本代码时,就会产生XSS攻击。
例如,攻击者可以在一个论坛的回复框中输入一段恶意的脚本代码,然后当其他用户在查看该回复时,就会执行这段脚本代
码,从而导致攻击者获取用户的Cookie等敏感信息
具体来说,网站可以采用以下几种方式来防止XSS攻击:
总之,要防止XSS攻击,网站开发者需要充分了解XSS攻击的原理,并采取一系列的措施来确保网站的安全性
CSRF(Cross Site Request Forgery),跨站请求伪造
跨站请求伪造(Cross-Site Request Forgery,CSRF)是一种网络攻击方式,它通常会利用用户已经登录过的身份,来执行一
些恶意操作,比如删除账户、购买商品等。
攻击者会在一个恶意网站中构造一个请求,然后引诱用户在已登录的另一个网站上点击一个链接,这个链接会让用户在不知情
的情况下发送请求到目标网站,这时候目标网站会认为这个请求是合法的,因为它携带了用户已经登录的身份信息,从而执行
攻击者想要的操作。
例如,一个攻击者可以在一个恶意网站中构造一个请求,这个请求可以让用户在另一个网站上删除自己的账户,然后攻击者就
会通过这种方式来盗取用户的账户。
为了防止CSRF攻击,网站通常会采取一些防范措施,比如添加随机令牌、验证Referer头、验证请求的来源地址等。
Ajax 即“AsynchronousJavascriptAndXML”
(异步 JavaScript 和 XML),是指一种创建交互式网页应用的开发技术。它是
一种在无需重新加载整个网页的情况下,能够更新部分网页的技术。通过在后台与服务器进行少量数据交换,Ajax 可以使网页
实现异步更新。传统的网页(不使用 Ajax)如果需要更新内容,必须重载整个网页页面。其缺点如下:
fetch号称是AJAX的替代品,是在ES6出现的,使用了ES6中的promise对象。Fetch是基于promise设计的。Fetch的代码结构比起ajax简单多。fetch不是ajax的进一步封装,而是原生js,没有使用XMLHttpRequest对象。
fetch的优点:
fetch的缺点:
Node.js是一个基于Chrome V8引擎的JavaScript运行时环境,它允许JavaScript在服务器端运行。Node.js的主要用途是编写服
务器端应用程序,但它也可以用于编写命令行工具、网络工具和桌面应用程序等。
Node.js中的包管理器是npm
(Node Package Manager
)。它是一个用于安装、管理和分享Node.js模块的工具。npm
允许你
通过命令行安装、卸载和更新模块,还可以搜索和分享你的模块。npm
还可以自动解决依赖关系,并在安装时将所有需要的模
块下载到本地。它们可以提高数据处理的效率和安全性。
答:缓冲区是Node.js中用于处理二进制数据的机制。缓冲区是一个固定大小的内存块,它可以存储任意类型的数据,包括
ASCII、UTF-8和16进制等。缓冲区可以用于处理文件、网络数据和其他I/O操作,它们可以提高数据处理的效率和安全性。
在 Node.js 中,异步操作通常通过回调函数来处理。当一个异步操作完成后,会调用回调函数,并将操作结果传递给回调函
数。开发人员可以在回调函数中处理异步操作的结果,例如输出结果、更新数据等。除了回调函数,Node.js
还提供了
Promise
、Async/Await
等方式来处理异步操作
我们分为三大模块,分别是核心模块、自定义模块和第三方模块。
模块是指一个包含代码的文件或者文件夹。每个模块都拥有自己的作用域,可以通过 require
函数来加载模
块,并使用模块中的代码。可以通过 exports
或 module.exports
对象来向外暴露模块中的内容,其他模块可以通过 require
函
数来引用模块中的内容。
webpack
是一个打包模块化 javascript
的工具,在webpack里一切文件皆模块,通过loader
转换文件,通过plugin
注入钩子,最后输出由多个模块组合成的文件,webpack
专注构建模块化项目
Webpack 的运行流程是一个串行的过程,从启动到结束会依次执行以下流程:
1. 初始化参数:从配置文件读取与合并参数,得出最终的参数
2. 开始编译:用上一步得到的参数初始化 Compiler 对象,加载所有配置的插件,开始执行编译
3. 确定入口:根据配置中的 entry 找出所有的入口文件
4. 编译模块:从入口文件出发,调用所有配置的 Loader 对模块进行翻译,再找出该模块依赖的模块,再递归本步骤直到所有入口依赖的文件都经过了本步骤的处理
5. 完成模块编译:在经过第4步使用 Loader 翻译完所有模块后,得到了每个模块被翻译后的最终内容以及它们之间的依赖关系
6. 输出资源:根据入口和模块之间的依赖关系,组装成一个个包含多个模块的 Chunk,再把每个 Chunk 转换成一个单独的文件加入到输出列表,这步是可以修改输出内容的最后机会
7. 输出完成:在确定好输出内容后,根据配置确定输出的路径和文件名,把文件内容写入到文件系统。
在以上过程中,Webpack 会在特定的时间点广播出特定的事件,插件在监听到感兴趣的事件后会执行特定的逻辑,并且插件可以调用 Webpack 提供的 API 改变 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。
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更倾向于前端开发者的思路
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 代码
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的实例,参数都通过构造函数传入。
当 Render Tree
(渲染树)中部分或者全部元素的布局,尺寸大小,结构等发生改变时,浏览器就会重新渲染部分或全部文档的过程称为 回流。
页面中元素的颜色,字体,或其他外观属性改变时,浏览器需要重绘来更新外观(比如:color、background-color、outline
等), 称为重绘。
重绘不一定引起回流(重排),而回流(重排)一定会引起重绘。
1.1 页面的首次刷新
1.2 浏览器的窗口大小发生改变
1.3 元素的大小或位置发生改变
1.4 改变字体的大小
1.5 内容的变化(如:input
框的输入,图片的大小)
1.6激活css
伪类 (如::hover
)
1.7 脚本操作DOM
(添加或者删除可见的DOM
元素)
1.8 简单理解影响到布局了,就会有回流
跨域:指的是浏览器不能执行其他网站的脚本。它是由浏览器的同源策略造成的,是浏览器对 javascript 施加的安全限制。
通俗的说就是协议 端口 主机 三者 不一致就会造成跨域
解决方案:
Header[Access-Control-Allow-Origin]
来告诉客户端跨域的限制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
中由于需要展示内容而涉及的业务逻辑。
Vue.js
是一个渐进式的 JavaScript
框架,旨在通过尽可能简单的 API
实现响应式数据绑定和组合的视图组件。
Vue.js
的核心是数据驱动视图,通过组件内特定的方法实现视图和模型的交互 。
Vue.js
的响应式系统可以在模型数据变化时,视图会自动更新。这意味着,我们可以在不手动操作 DOM
的情况下改变视图。
Vue.js
还提供了许多其他功能,如组件系统、路由、状态管理等,可以帮助你构建复杂的单页应用。
总的来说,Vue.js
是一个轻量级的、易于使用的前端框架,可以帮助你快速构建响应式的 Web
应用。
v-bind:
绑定属性v-if
、v-show:
条件渲染v-for:
列表渲染v-model:
双向绑定v-html:
解析html字符串v-on:
绑定事件vue 是一个单页面应用 ,这个vue项目其实只会有一个 index.html 页面,它内容的切换本质都是通过切换div来实现模拟多页面的
SPA单页面应用(SinglePage Web Application
,简称 SPA
),指的是只有一个主页面的应用,一开始只需要加载一次js
、css
等相关资源,所有内容都包含在主页面上,对每一个功能模块组件化,单页面应用跳转,就是切换相关组件,仅仅刷新局部资源。(单页面应用指一个系统只加载一次资源,然后下面的操作交互、数据交互是通过router、ajax来进行,页面并没有刷新)
与传统的多页面应用相比,单页面应用具有许多优势,包括:
然而,单页面应用也有一些缺点,包括:
SPA
应用的代码都在客户端运行,因此调试可能会更加困难。SEO
难度较大: 由于所有的内容都在一个页面上动态替换显示,所以在 SEO
上其有着天然的弱势。 为了解决这个问题,可以使用服务端渲染(Server-Side Rendering,简称 SSR
)技术,在服务器端渲染 SPA
应用的内容,使得爬虫可以正常抓取页面内容。在vue2
中v-for
优先级高于v-if
,如果二者在同一级标签里面使用,每次都要先循环,再判断,消耗很多性能。
解决办法的话,可以在外层包装一个div
,使用v-if
做一次判断即可。Vue3
解决了这个问题,将v-if
的优先级调整为高于v-for
了。
computed
是用来计算出来一个值的,这个值调用的时候不需要加括号,会根据依赖进行缓存,依赖不变,computed
的值不会重新计算。
watch
是来监听的,有2个选项
immediate
:表示是否要在第一次渲染的时候执行这个函数deep
:如果我们监听一个对象,那么我们要看这个对象里面的属性是否变化,如果某个属性变化了,就去执行一个函数在 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 对象,组件之间的状态就不会混乱了。
nextTick 是 Vue.js 中一个用来在下一个事件循环中调用回调函数的方法。( 就是你放在 $ nextTick 当中的操作不会立即执行,而是等数据更新、DOM更新完成之后再执行,这样我们拿到的肯定就是最新的了 )这个方法通常用在等待数据或 DOM 元素更新之后执行一些代码。也可以说在下一次DOM更新结束后执行其指定的回调
这句话扩展开来说,就是由于Vue中DOM更新是「异步执行」的,即修改数据时,视图不会立即更新,而是会监听数据变化,并缓存在同一事件循环中,等同一数据循环中的所有数据变化完成之后,再统一进行视图更新。经常我们会在还未更新的时候就使用了某个元素,这样是拿不到变更后的dom的,所以为了确保能够得到更新后的DOM,所以设置了nextTick()方法。在修改数据之后立即使用这个方法,获取更新后的DOM。简单概括,vue中的nextTick主要用于处理数据动态变化后,DOM还未及时更新的问题,用nextTick可以获取数据更新后最新dom的变化。
在 Vue.js 中,插槽(slot
)是一种机制,可以在父组件的模板中定义一个占位符,然后在子组件中插入内容。这样,子组件就
可以在父组件的模板中渲染内容,使得子组件可以更灵活地与父组件进行交互。
插槽有两种类型:
#
”,#以及#后面的字符称之为 hash
,又叫前端路由window.location.hash
读取URL
中,但不会向服务器发送请求hashchange
事件, 并根据hash值来修改页面内容url
都会被浏览器记录下来,从而实现浏览器的前进后退。HTML5
History
API
url
里放参数,还可以将数据存放在一个特定的对象中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函数替代了
Vue
会尽可能的就地(同层级,同位置),对比虚拟dom
,复用旧dom
结构,进行差异化更新,vue
采用的是diff算法进行对比。它会先同层级根元素进行比较,如果根元素变化的话,就不考虑复用了,如果根元素没有变化,就会对比同级兄弟元素,默认按照下标进行对比复用,如果设置了key
就会按照相同key
的新旧元素进行对比复用,key
必须是一个唯一不重复的字符串或者数值,key
的好处就是可以提高虚拟DOM
对比的复用性能。
deep
(深度侦听):默认情况下,侦听器无法侦听对象的属性值的变化,如果想实现这个效果,则需要添加deep
配置为true
handler
(固定方法触发):因为你要添加deep
的配置,所以,侦听器的形式要变更为对象形式,只有对象才能添加其它的配置, 同时侦听函数必须为handler
immediate
(立即侦听):如果需要默认一进页面就触发一次,添加immediate
配置选项为true
全局前置路由守卫: 初始化的时候被调用,每次 路由切换之前 被调用。
路由跳转之前, 会触发的一个函数 叫前置路由守卫
语法:router.beforeEach((to, from, next) => {这里可以写路径的跳转判断/有无token值的情况分析})
作用 : 防止别人猜到网址的hash值后直接跳过登录就可以查看数据
里面的3个参数:
to
: 到哪里去
from
: 从哪里来
next
: 放行函数 next()
:放行 , next(false)
:不放行
state
,一个是payload
,通过store.commit
调用store
,一个是payload
,通过store.dispatch
调用,在actions
里也可以提交mutation
,通过store.commit
vuex
模块化,可以让每一个模块拥有自己的state
、mutation
、action
、getters
,结构清晰,方便管理优点
缺点
我们通常是将数据保存到本地存储中,当重新刷新页面后再从本地存储中将之前的数据加载回来
保存到vuex
中的state
中。这样就能实现vuex
的数据持久化了
三次握手是用于在俩台计算机之间建立网络连接
, 确认双方的接收与发送能力是否正常 ,它包括三个步骤:
1.客户端向服务端发送连接请求
2.服务端向客户端发送确认消息,表明服务器已准备好接受连接
3.客户端向服务器发送确认消息,表明客户端已收到服务端的确认消息,并准备好开始数据传输
四次挥手是用于在俩台计算机之间终止网络连接
,它包括以下四个步骤:
1.客户端向服务器发送断开连接请求
2.服务器向客户端发送确认消息,表明服务器已收到断开连接的请求。(服务端收到关闭请求的时候可能这个时候数据还没发送完,所以服务端会先回复一个确认报文,表示自己知道客户端想要关闭连接了,但需要等待数据传输完)
3.服务器向客户端发送断开连接的请求。(会主动发送FIN报文,告知客户端,服务端准备关闭连接了)
4.客户端向服务器发送确认消息,表明客户端已收到服务器的断开连接请求,稍后进行断开
因为当服务端收到客户端的SYN连接请求报文后,可以直接发送SYN+ACK报文。其中ACK报文是用来应答的,SYN报文是用来同步的。但是关闭连接时,当服务端收到FIN报文时,很可能并不会立即关闭SOCKET,所以只能先回复一个ACK报文,告诉客户端,“你发的FIN报文我收到了”。只有等到我服务端所有的报文都发送完了,我才能发送FIN报文,因此不能一起发送。故需要四次挥手。
TCP
和UDP
都是传输层协议
TCP
是一种面向有连接的传输层协议,能够对自己提供的连接实施控制。适用于要求可靠传输的应用,例如文件传输。面向字节流,传输慢 。
UDP
是一种面向无连接的传输层协议,不会对自己提供的连接实施控制。适用于实时应用,例如:IP电话、视频会议、直播等。,以报文的方式传输,效率高 。
UDP | TCP | |
---|---|---|
是否连接 | 无连接 | 面向连接 |
是否可靠 | 不可靠传输,不使用流量控制和拥塞控制 | 可靠传输,使用流量控制和拥塞控制 |
连接对象个数 | 一对一,一对多,多对一,多对多 | 只能有俩个端点,一对一通信 |
传输方式 | 面向报文 | 面向字节流 |
首部开销 | 开销小,仅8字节 | 最小20字节,最大60字节 |
1、URL解析:地址栏输入地址,浏览器对输入内容进行解析,判断URL的合法性,和是否有可用缓存
2、DNS解析:域名解析系统(DNS)查找对应的IP地址
3、建立TCP连接(三次握手):浏览器向服务器发起TCP连接,与浏览器建立TCP三次握手
4、HTTP请求:浏览器将http请求数据发给服务器(客户端–>服务器)
5、HTTP响应:服务器处理收到的请求,返回响应结果至浏览器(服务器–>客户端)
6、关闭TCP连接(四次挥手):数据传输完成后,还要经过四次握手以终止连接
7、页面渲染:浏览器解析响应结果,进行页面渲染
比如说,当在输入框输入文字时,vue会检测到数据的变化,然后更新对应的视图。同样,如果你通过代码修改了数据,那么vue
也会自动更新视图,其原理是通过数据劫持和发布订阅模式实现的。
首先,Vue
通过Object.defineProperty( )
方法对数据进行劫持,监听数据的变化,并通过getter
和setter
方法对数据进行读写。
其次,Vue通过发布订阅模式,维护了一个订阅者数组,当数据发生变化时,Vue
会通知所有订阅者进行更新。因此,当用户在页面上进行修改时,Vue
也会自动更新对应的数据,并通知所有订阅者更新视图,同时当数据发生变化时,Vue也会更新对应的视图,通过这样的机制,Vue实现了双向数据绑定,使得数据和视图的变化可以互相影响
补充:订阅者是Vue中的一个概念,它是一个用于管理更新视图的对象,当数据发生变化时,Vue会通知所有的订阅者进行更新,在Vue中,每一个挂载到视图上的组件,或者每一个watcher,都可以被看成一个订阅者,他们订阅了某一个数据的变化,并等待数据发生变化时进行更新,订阅者是Vue实现双向数据绑定的关键组成部分,管理着数据和视图之间的关系,保证了数据的变化能够及时反应到视图上
是数据劫持加观察者模式实现的。 大致分成了以下两步:
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
针对某个属性, 只需要做一层代理就可以监听同级结构下的所有属性变化,。
作用:都是可以实现元素的显示与隐藏
v-show
频繁切换标签,用v-show
css手段控制标签显示隐藏v-if
不频繁切换标签,用v-if,创建删除标签显示隐藏,惰性的,一开始为false的,不会创建标签,性能更好在 Vue.js
中,v-model
指令是一种语法糖,它的作用是为表单元素绑定双向数据绑定。v-model
指令的实现原理是基于计算属性和事件绑定。它会将表单元素的 value
属性绑定到一个计算属性上,并且在计算属性的 setter
中触发 input
事件来更新 Vue 实例中的数据。
vue2
有使用过滤器 vue3
已舍弃使用
vue2
过滤器的使用:用于一些常见的文本格式化 例如:日期格式化、数字大小写、单位转换、文本格式化等
过滤器的作用:可以在不改变原数据 只是对数据进行加工处理并返回过滤后的数据,再进行调用处理
过滤器分为全局过滤器和局部过滤器
过滤器只能应用在两个地方:双花括号插值
和v-bind
表达式(后者从 2.1.0+ 开始支持)。例如
<div>{{3 | addZero}}div>
<div v-bind:id="1 | addZero">11div>