1.什么是事件循环
事件循环是 JavaScript 中一种异步执行机制,它的作用是协调和管理各种异步任务的执行顺序,保证 JavaScript 代码的执行顺序和预期一致。
JavaScript 代码执行时会先执行同步任务,而异步任务则被放入任务队列中等待执行。事件循环机制会不断地检查任务队列中是否有任务需要执行,如果有,则将任务取出并执行。在执行异步任务时,JavaScript 引擎会挂起当前任务的执行,去执行异步任务,等到异步任务执行完成后,再回到之前的任务继续执行。
事件循环由三部分组成:调用栈、任务队列和事件循环线程。调用栈用来管理代码的执行顺序,任务队列用来存放异步任务,事件循环线程则是一个循环,不断地从任务队列中取出任务执行。
当 JavaScript 代码执行时,如果遇到一个异步任务,如 setTimeout(),则会将任务添加到任务队列中,等待执行。在 JavaScript 引擎空闲时,事件循环线程会不断地从任务队列中取出任务,放入调用栈中执行,直到任务队列为空为止。
需要注意的是,任务队列中的任务分为两种类型:宏任务和微任务。宏任务包括 setTimeout()、setInterval()、XMLHttpRequest 等异步任务,而微任务包括 Promise、MutationObserver 等异步任务。在事件循环过程中,当一个宏任务执行完成后,会先执行所有微任务,然后再从任务队列中取出下一个宏任务执行
总之,事件循环是 JavaScript 中一种重要的异步执行机制,它通过协调和管理异步任务的执行顺序,保证 JavaScript 代码的执行顺序和预期一致,从而提高了 JavaScript 代码的可靠性和稳定性。
2.从url到页面经历了什么过程
-
-
浏览器根据域名找到对应的 ip 地址(远程服务器)
ip 指的是网络为每一台电脑分配的一个地址。由于 ip 地址不容易被记住,所以有了域名,浏览器拿到域名后,首先要先把域名解析成 ip,然后找到 ip 对应的机器。解析域名通常使用的方法是 DNS 解析,为了让查找过程更高效,浏览器和操作系统都会将每次的解析结果缓存起来,在下次解析的时候,就会先从缓存中去查找 ip(解析方式:查找本地缓存中 ——> DNS数据缓存中 ——> DNS解析对应ip)。
-
-
- 浏览器与远程服务器建立连接(tcp连接 三次握手)
找到对应的 ip 后,就要建立 TCP 连接了,只有连接成功,双方才可以发送数据。连接分为三次,分别是浏览器向服务器端发送 SYN 请求;服务器接收到请求后,会向浏览器端发送 SYN/ACK 数据包进行确认信息;最后浏览器会向服务器端传入 ACK 数据包来表示可以通信了。
-
- 浏览器与远程服务器发送和接收数据
建立连接后,浏览器和服务器就可以进行通信了。浏览器通过向服务器发送 http 请求,从而获得响应数据。这其中的过程包含了:请求报文(请求行、请求头、主体)、响应报文(状态行、响应头、响应正文)。
-
- 浏览器与远程服务器断开连接(tcp断开 四次挥手)
两端通信结束之后,为了不浪费系统资源,就需要考虑断开连接了。TCP 的断开分为四次,因为在浏览器向服务器端发出可以断开连接信息的时候,服务器可能还存在一些数据没有传输完成,这时服务器需要去确认一下数据是否全都传输完成,如果全都完成了,服务器才会告诉浏览器可以断开了。
-
- 浏览器渲染
1)构建 DOM 树:渲染进程将 HTML 内容转换为能够读懂的 DOM 树结构;
2)样式计算:渲染引擎将 CSS 样式表转化为浏览器可以理解的 styleSheets,计算出 DOM 节点的样式;
3)布局阶段:创建布局树,并计算元素的布局信息;(排除script、meta等功能化和非视觉节点)
4)分层:对布局树进行分层,并生成分层树;(生成图层树,因为有不同的层级要求)
5)栅格化:合并线程将图层分图块,并栅格化将图块转换成位图;(视图进行分割)
6)显示:合并线程发送绘制图块命令给浏览器进程。浏览器进程根据指令生成页面,并显示在页面;
3.闭包及其应用场景
- 闭包还用用场景
我们有时候需要得到函数内的局部变量,但是在正常情况下,这是不能读取到的,这时候就需要用到闭包。在javascript语言中,只有函数内部的子函数才能读取局部变量,因此可以把闭包简单理解成“定义在一个函数内部的函数”。闭包是指有权访问另一个函数作用域中的变量的函数。其本质是函数的作用域链中保存着外部函数变量对象的引用。
闭包使用场景1,封装对象的私有属性和方法
隐藏数据
做一个简单的缓存工具
闭包应用场景2,闭包作用回调函数
闭包应用场景3,函数节流防抖
- 闭包优缺点 闭包的优点:
1.变量长期驻扎在内存中
2.另一个就是可以重复使用变量,并且不会造成变量污染
①全局变量可以重复使用,但是容易造成变量污染。不同的地方定义了相同的全局变量,这样就会产生混乱。 ②局部变量仅在局部作用域内有效,不可以重复使用,不会造成变量污染。 ③闭包结合了全局变量和局部变量的优点。可以重复使用变量,并且不会造成变量污染。
闭包的缺点:
由于闭包会使得函数中的变量都被保存在内存中,内存消耗很大,所以不能滥用闭包,否则会造成网页的性能问题,在IE中可能导致内存泄露。解决方法是,在退出函数之前,将不使用的局部变量全部删除。
4.防抖节流
- 防抖 函数防抖是指在函数被高频触发时当停止触发后延时n秒再执行函数,(即每次触发都清理延时函数再次开始计时),一般用于resize scroll,mousemove
函数防抖:是函数在特定的时间内不被再调用后执行
- 节流 函数节流 原理 函数被高频触发时延时n秒后才会再次执行,防抖主要是用户触发一次时间后,延迟一段时间触发,而节流会规定的时间内触发一次事件
函数节流:是确保函数特定的时间内至多执行一次。
5.ES6新增特性
- 总结
- es6新增了promise(标题) 需要说什么是promise
- es6新增了模块化 需要说什么是模块化
- 新增了class关键字 需要解释
- 新增了箭头函数 再说箭头函数与普通函数的区别
- 新增了解构赋值 需要解释什么是解构赋值
- 新增了let const关键字 需要说let const var的区别
- 新增了简单数据类型symbol
1、新增了let const关键字
let var const的区别 let 是代码块有效 var是全局有效 let 是不能重复声明的 var是可以多次声明 let不存在变量的提升 var存在变量的提升 const存储简单数据类型存储的是常量
2、新增的解构赋值
解构赋值针对数组或者对象进行模式匹配,然后对其中的变量进行赋值。
let [a,b]=[1,2]
let {user}={user:“xiaosi”}
3、新增了箭头函数
箭头函数和普通函数的区别
普通函数存在着变量的提升,箭头函数没有 普通函数的this指向,谁调用指向谁,箭头函数是在哪定义就指向谁 普通函数可以当成构造函数,而箭头函数是不可以的 箭头函数没有arguments,要接受所有的参数用...rest
4、js的数据类型
简单数据类型 Number 、 String 、 Boolean 、 null 、undefined 、Symbol
引用数据类型 Object Array Function Date RegExp
5、数据类型判断 (得准确的知道每一种数据类型判断缺点)
typeof 能判断基本的数据类型,返回基本数据类型小写字符串形式 除了null,用typeof判断null 返回Object instanceof 可以判断引用数据类型 正常的判断A是B的实例是没有问题的,但是所有引用数据类型的对象用instanceof判断都是Object的实例 constructor 构造函数可以判断除了undefined 和null之外的任何数据类型,页解决了instanceof的问题 最完美的解决方案 Object.prototype.toString.call()返回的是[ Object 数据类型]
6、es6新增了模块化
根据功能封装模块 通过import导入 然后通过export导出
可以使用 export 导出也可以使用export default导出
我们使用import 来导入
export 和 export defualt的区别
export 可以导出多个属性或者方法 ,需要用{}括起来 在用import接受的时候也得用{}接受 export default是以整体的方式抛出,接受的时候只接一个
7、promise
promise是es6处理异步的一种方式,它的本质是一个对象,promise的参数是一个回调,回调有连个参数 resolve 成功回调 reject 失败回调。它有三种状态分别为 初始状态pending 已完成fulfilled 已失败rejected。状态改变只有两种结果 完成或者失败。
promise处理错误的方式有两种 第一种在then中传递两个回调 第二个回调是错误回调
第二种方式是通过catch方式来实现
promise常用的api有 then ()处理回调函数 catch()捕获异常 还有两个常用的静态方法
Promise.all()一块处理多个promise请求,所有的请求都成功才成功。
Promise.race()一块处理多个promise请求,有一个成功就成功
es7中可以使用async实现异步处理,还有一个关键字await可以实现异步函数同步化
8、新增类class关键字
class关键字是es5构造函数+原型模式创建对象的语法糖。创建类的方式 class 类名{构造函数和方法} 通过extends关键字实现继承。
需要录制的面试题:
js的数据类型 js的数据类型判断 箭头函数与普通函数的区别 let const var的区别 promise
9、es6新增哪些特性?
es6新增了promise(标题) 需要说什么是promise es6新增了模块化 需要说什么是模块化 新增了class关键字 需要解释 新增了箭头函数 再说箭头函数与普通函数的区别 新增了解构赋值 需要解释什么是解构赋值 新增了let const关键字 需要说let const var的区别 新增了简单数据类型symbol
10、作用域与作用域链
作用域:就是变量的使用范围。js中作用域分为全局和局部
js的作用域分为全局作用域和局部作用域。在全局作用域中是不能访问局部作用域中的数据。在局部作用域中访问变量如果当前作用域中有可以直接访问,如果没有那么向上级作用域中访问,如果上级作用域也没有就继续向上找,知道找到全局window作用域,如果window作用域也没有返回undefined,整个作用域的访问形成了一个作用域链
11、说一下闭包
概念
闭包是指有权访问另外一个函数作用域中的变量的函数。可以理解为(能够读取另一个函数作用域的变量的函数)
特性
1:函数套函数
2:内部函数可以直接访问外部函数的内部变量或参数
3:变量或参数不会被垃圾回收机制回收
定义
Plain Text
优缺点
优点:
1:变量长期驻扎在内存中
2:避免全局变量的污染
3:私有成员的存在
缺点:
常驻内存 增大内存的使用量 使用不当会造成内存的泄露.
12、原型与原型链
原型:每一个对象都有一个prototype属性可以挂载要扩展的属性和方法,在prototype上挂载的属性和方法在这个对象的任何实例上都可以调用。
当一个对象调用自身不存在的属性/方法时,就会去prototype关联的父类对象上去找,如果找不到继续去父类关联的对象上去找,直到找到Object的属性和方法,找到直到调用,找不到返回undefined
13、对象的浅拷贝与深拷贝
由于引用数据类型的数据是存储在堆空间中,在栈空间中存储的是是数据的引用地址。
对象的浅拷贝就是将栈空间中的地址复制一份,两个地址指向的同一个数据
浅拷贝可以使用Object.assign()来实现 深拷贝可以使用JSON.stringify()先转换为json的串复制,然后再通过JSON.parse()转换回来
14、说一下js的事件机制
js中存在两种事件机制,一个是ie提出的冒泡事件机制 还有一个是网景提出的捕获型事件机制
冒泡事件机制是先触发事件的的直接元素,然后向外扩散就像冒泡一样。捕获型就是事件从外向里执行。js中的事件监听addEventListener的第三个参数默认的为false 是冒泡 为true是捕获
我们可以通过event.stopPropagation()来实现
15、rem布局的原理
1rem的大小就是根元素的font-size的值,通过设置 根元素的font-size的大小,来控制整个html文档内的字体大小、元素宽高、内外边距等
16、如何实现响应式布局
响应式布局可以让网站同时适配不同分辨率和不同的手机端,让客户有更好的体验
响应式布局实现的方案:
百分比布局 媒体查询 rem布局 vw vh布局 flex弹性盒布局
17、router的区别
route对象,是一个局部的对象,可以获取对应的name,path,params,query等
$router是VueRouter的一个对象,通过Vue.use(VueRouter)和Vue构造函数得到一个router的实例对象,这个对象中是一个全局的对象,他包含了所有的路由,包含了许多关键的对象和属性。
18、params和query传参的区别
params传值的参数是路由的一部分,所以调转必须加参数值才能调转 query传参和路由配置没有关系 获取方式是不一样的 query this.route.params.参数名
19、mpa和spa的区别
mpa 多页面应用
一套系统有多个页面组成,页面之间的切换是由a标签的herf属性和script的location.href来实现的
spa是单页面应用
一套系统就由一个页面来承载,数据的切换是由路由来实现
mpa与spa的优缺点:
对于切换来说,路由的切换肯定比页面的切换更顺畅 所以spa的切换会好 spa的首屏加载慢,mpa的首屏加载快
6.跨域
-
什么是跨域
跨域就是当在页面上发送ajax请求时,由于浏览器同源策略的限制,要求当前页面和服务端必须同源,也就是协议、域名和端口号必须一致。
如果协议、域名和端口号中有其中一个不一致,则浏览器视为跨域,进行拦截。
- 跨域解决解决方法
-
总结:
-
jsonp的原理是利用了script标签不受浏览器同源策略的限制,img和link标签也是不受浏览器同源策略限制的。
-
跨域是浏览器限制,服务端和服务端之间通信是不受浏览器同源策略限制的。 所有跨域的解决方案都是需要服务端配合的。
-
最常用的跨域解决方案是CORS、Node代理服务器和Nginx反向代理方式。
-
postMessage更多的是用在多个文档,窗口之间发送数据。
1.JSONP方式解决跨域:
jsonp的原理就是利用了script标签不受浏览器同源策略的限制,然后和后端一起配合来解决跨域问题的。
具体的实现就是在客户端创建一个script标签,然后把请求后端的接口拼接一个回调函数名称作为参数传给后端,并且赋值给script标签的src属性,然后把script标签添加到body中,当后端接收到客户端的请求时,会解析得到回调函数名称,然后把数据和回调函数名称拼接成函数调用的形式返回,客户端解析后会调用定义好的回调函数,然后在回调函数中就可以获取到后端返回的数据了。
-
优缺点
jsonp的优点就是兼容性好,可以解决主流浏览器的跨域问题,缺点是仅支持GET请求,不安全,可能遭受xss攻击
2.CORS方式解决跨域:
cors是跨域资源共享,是一种基于 HTTP 头的机制,该机制通过允许服务器标示除了它自己以外的其它 origin(域,协议和端口),使得浏览器允许这些 origin 访问加载自己的资源。服务端设置了Access-Control-Allow-Origin就开启了CORS,所以这种方式只要后端实现了CORS,就解决跨域问题,前端不需要配置。
3.搭建Node代理服务器解决跨域:
因为同源策略是浏览器限制的,所以服务端请求服务器是不受浏览器同源策略的限制的,因此我们可以搭建一个自己的node服务器来代理访问服务器。
大概的流程就是:我们在客户端请求自己的node代理服务器,然后在node代理服务器中转发客户端的请求访问服务器,服务器处理请求后给代理服务器响应数据,然后在代理服务器中把服务器响应的数据再返回给客户端。客户端和自己搭建的代理服务器之间也存在跨域问题,所以需要在代理服务器中设置CORS。
4.Nginx反向代理解决跨域:
nginx通过反向代理解决跨域也是利用了服务器请求服务器不受浏览器同源策略的限制实现的。
客户端请求nginx服务器,在nginx.conf配置文件中配置server监听客户端的请求,然后把location匹配的路径代理到真实的服务器,服务器处理请求后返回数据,nginx再把数据给客户端返回。
7.promise
-
promise是js中解决异步编程的新解决方案(旧的方案是单纯的调用回调函数)
-
为什么要用promise? 1.promise支持链式调用,解决回调地狱问题
-
promise 状态改变
-
总结:promise对象有三个状态,并且状态一旦被改变,就不能再被改为其他状态
1.pending 异步任务正在进行。(未决定的)
2.resolved 异步任务执行成功。
3.rejected 异步任务执行失败
- Promise状态改变只有 pending 变为 resolved 和 pending 变为 rejected 这两种 且一个 Promise 对象只能改变一次,无论成功或者失败都会有一个结果数据,成功的结果数据一般称为 value,失败的结果数据一般称为 reason。
promise的API
1.promise构造函数
-
executor函数:执行器
-
resolve函数:内部定义成功时执行的函数
-
reject函数:内部定义失败执行的函数
2.then()
* 指定用于得到成功 value 的成功回调和用于得到失败 reason 的失败回调,返回 一个新的 promise 对象。
3.catch()
-
catch() 方法返回一个
Promise,并且处理拒绝的情况。 -
它的行为与调用
Promise.prototype.then(undefined, onRejected)相同。他只能用来指定失败的回调同样支持链式调用,本质上其实是then()方法的一个单独封装
4.resolve()
* 这个方法比较特殊,它是属于 Promise 这个函数对象的,并不属于实例对象,也就是说它是静态成员。
- 用法:接收一个参数,返回一个promise成功或者失败对象
5.reject()
-
这个方法和上面的
Promise.resolve方法一样,是属于 Promise 这个函数对象的,不属于实例对象,同样为静态成员。 -
用法:快速返回一个带有拒绝原因的promise对象
5.all()
-
总结:返回一个新的 promise ,只有所有的 promise 都成功才成功,只要有一个失败了就直接失败
-
这个方法也是属于 Promise 函数对象的,不属于实例对象。
-
Promise.all()方法接收一个promise的iterable类型(注:Array,Map,Set都属于ES6的iterable类型)的输入,并且只返回一个Promise实例, 那个输入的所有promise的resolve回调的结果是一个数组。这个Promise的resolve回调执行是在所有输入的promise的resolve回调都结束,或者输入的iterable里没有promise了的时候。它的reject回调执行是,只要任何一个输入的promise的reject回调执行或者输入不合法的promise就会立即抛出错误,并且reject的是第一个抛出的错误信息。
语法:Promise.all(iterable)
iterable: 一般为包含 n 个 promise 的数组
6.rece()
- 总结:返回一个新的 promise,第一个完成的promise的结果状态就是最终的结果状态
就相当于在传入的promise对象在赛跑,谁先改变状态,谁就决定race方法的返回结果,无论是成功或者失败。
- 这个方法也是属于 Promise 函数对象的,不属于实例对象。
语法:Promise.race(iterable);
iterable: 包含 n 个 promise 的数组
promise中的几个关键问题
1.如何改变promise对象的状态
let p = new Promise((resolve, reject) => {
// 1.resolve 函数
resolve('ok') // pending => resolved
// 2. reject 函数
reject('error') // pending => rejected
// 3. 抛出错误
throw '出问题了'
// 这三种方法都可以改变promise 的状态
})
2.能否执行多个回调
-
promise指定多个成功或失败的回调函数,都会调用吗?
-
当promise改变为对应状态时都会调用。
let p = new Promise((resolve, reject) => {
resolve('ok')
})
// 指定回调 - 1
p.then(value => {
console.log(value)
})
// 指定回调 - 2
p.then(value => {
alert(value)
})
// 很显然只要时promise的状态改变了,上面的两个回调函数都会执行
3.改变状态与执行回调顺序问题
-
改变promise状态和执行回调函数谁先谁后?
const p = new Promise((resolve, reject) => {
// 1. 当执行器中是一个同步任务的时候,那么会先改变状态再执行下面的then回调函数
resolve('ok')
// 2. 当执行器中时一个异步任务的时候,那么会先执行下面的then回调函数再改变状态
setTimeout(() => {
resolve('ok')
}, 1000)
})
p.then((value) => {
console.log(value)
}, (reason) => {
console.log(reason)
})
-
对于执行器中时一个异步任务的时候,我们先执行调用回调函数,但是要等到异步任务中resolve的状态改变之后,才会去执行回调函数里面的代码,然后对成功或失败的结果做处理
4.中断promise链的方法
const p = new Promise((resolve, reject) => {
resolve(123)
})
p.then(value => {
console.log(111)
// 中断promise链的唯一方法是返回一个pending状态的promise对象
// 因为如果返回的是pending,那么then方法返回的也是一个pending状态的promise对象
// 那么后续的then方法都不能执行,因为状态没有改变
return new Promise(() => {})
// 这时候就只会打印111
}).then(value => {
console.log(222)
}).then(value => {
console.log(333)
})
8.keep-alive
1.什么是keep-alive
keep-alive是Vue的内置组件,当它包裹动态组件时,会缓存不活动的组件实例,而不是销毁它们。keep-alive是一个抽象组件,它自身不会渲染一个DOM元素,也不会出现在父组件中。
2.作用
在组件切换过程中 把切换出去的组件保留在内存中,防止重复渲染DOM,减少加载时间及性能消耗,提高用户体验性
3.原理
在 created钩子函数调用时将需要缓存的 VNode 节点保存在 this.cache 中/在 render(页面渲染) 时,如果 VNode 的 name 符合缓存条件(可以用 include 以及 exclude 控制),则会从 this.cache 中取出之前缓存的 VNode实例进行渲染。
4.参数(Props)
- include - 字符串或正则表达式。只有名称匹配的组件会被缓存。
- exclude - 字符串或正则表达式。任何名称匹配的组件都不会被缓存。
- max - 数字。最多可以缓存多少组件实例
5.对生命周期的变化
1.activated
*在 keep-alive 组件激活时调用 该钩子函数在服务器端渲染期间不被调用
2.deactivated
-
在 keep-alive 组件停用时调用
-
该钩子在服务器端渲染期间不被调用
-
被包含在 keep-alive 中创建的组件,会多出两个生命周期的钩子: activated 与 deactivated
-
使用 keep-alive 会将数据保留在内存中,如果要在每次进入页面的时候获取最新的数据,需要在 activated 阶段获取数据,承担原来 created 钩子函数中获取数据的任务。 注意:只有组件被 keep-alive 包裹时,这两个生命周期函数才会被调用,如果作为正常组件使用,是不会被调用的,以及在 2.1.0 版本之后,使用 exclude 排除之后,就算被包裹在 keep-alive 中,这两个钩子函数依然不会被调用!另外,在服务端渲染时,此钩子函数也不会被调用。
9.改变this指向的三个方法
总结:
-
1、call方法在调用的时候会执行函数 第一个参数是this的指向 第二个参数以及后面的参数都是需要传的参数 返回值是原函数中定义的返回值
-
2、apply方法在调用的时候也会执行函数 第一个参数是this的指向 第二个参数是数组 其中是需要传递的参数 返回值是原函数中定义的返回值
-
3、bind方法在调用的时候不会执行函数 第一个参数是this的指向 第二个参数
10.git指令
1、第一次初始化
- git init
git add .
git commit -m ‘first commit’
git remote add origin git@github.com:帐号名/仓库名.git
git pull origin master
git push origin master # -f 强推 - git clone git@github.com:git帐号名/仓库名.git
2、工作基本操作
- git checkout master 切到主分支
- git fetch origin 获取最新变更
- git checkout -b dev origin/master 基于主分支创建dev分支
- git add . 添加到缓存
- git commit -m ‘xxx’ 提交到本地仓库
- git fetch origin 获取最新变更
3、初始化仓库
git init
4、查看仓库当前状态
git status
5、文件相关操作
将文件添加到仓库:
- git add 文件名 将工作区的某个文件添加到暂存区
- git add . 将当前工作区的所有文件都加入暂存区
- git add -u 添加所有被tracked文件中被修改或删除的文件信息到暂存区,不处理untracked的文件
- git add -A 添加所有被tracked文件中被修改或删除的文件信息到暂存区,包括untracked的文件
- git add -i 进入交互界面模式,按需添加文件到缓存区
将暂存区文件提交到本地仓库:
- git commit -m “提交说明” 将暂存区内容提交到本地仓库
- git commit -a -m “提交说明” 跳过缓存区操作,直接把工作区内容提交到本地仓库
比较文件异同
- git diff 工作区与暂存区的差异
- git diff 分支名 工作区与某分支的差异,远程分支这样写:remotes/origin/分支名
- git diff HEAD 工作区与HEAD指针指向的内容差异
- git diff 提交id 文件路径 工作区某文件当前版本与历史版本的差异
- git diff –stage 工作区文件与上次提交的差异(1.6 版本前用 –cached)
- git diff 版本TAG 查看从某个版本后都改动内容
- git diff 分支A 分支B 比较从分支A和分支B的差异(也支持比较两个TAG)
- git diff 分支A…分支B 比较两分支在分开后各自的改动
另外:如果只想统计哪些文件被改动,多少行被改动,可以添加 –stat 参数
6、查看历史记录
- git log 查看所有commit记录(SHA-A校验和,作者名称,邮箱,提交时间,提交说明)
- git log -p -次数 查看最近多少次的提交记录
- git log –stat 简略显示每次提交的内容更改
- git log –name-only 仅显示已修改的文件清单
- git log –name-status 显示新增,修改,删除的文件清单
- git log –oneline 让提交记录以精简的一行输出
- git log –graph –all –online 图形展示分支的合并历史
- git log –author=作者 查询作者的提交记录(和grep同时使用要加一个–all–match参数)
- git log –grep=过滤信息 列出提交信息中包含过滤信息的提交记录
- git log -S查询内容 和–grep类似,S和查询内容间没有空格
- git log fileName 查看某文件的修改记录
7、代码回滚
- git reset HEAD^ 恢复成上次提交的版本
- git reset HEAD^^ 恢复成上上次提交的版本,就是多个^,以此类推或用~次数
- git reflog
- git reset –hard 版本号
- –soft:只是改变HEAD指针指向,缓存区和工作区不变;
- –mixed:修改HEAD指针指向,暂存区内容丢失,工作区不变;
- –hard:修改HEAD指针指向,暂存区内容丢失,工作区恢复以前状态;
8、版本库相关操作
- 删除版本库文件:git rm 文件名
- 版本库里的版本替换工作区的版本:git checkout — test.txt
9、远程仓库相关操作
同步远程仓库:git push -u origin master
本地仓库内容推送到远程仓库:git remote add origin git@github.com:帐号名/仓库名.git
从远程仓库克隆项目到本地:git clone git@github.com:git帐号名/仓库名.git
查看远程库信息:git remote
拉取远程分支到本地仓库:
- git checkout -b 本地分支 远程分支 # 会在本地新建分支,并自动切换到该分支
- git fetch origin 远程分支:本地分支 # 会在本地新建分支,但不会自动切换,还需checkout
- git branch –set-upstream 本地分支 远程分支 # 建立本地分支与远程分支的链接
同步远程仓库更新::git fetch origin master
10、分支相关操作
创建分支:git checkout -b dev -b表示创建并切换分支
上面一条命令相当于一面的二条:
git branch dev 创建分支
git checkout dev 切换分支
查看分支:git branch
合并分支:
- git merge dev #用于合并指定分支到当前分支
- git merge –no-ff -m “merge with no-ff” dev #加上–no-ff参数就可以用普通模式合并,合并后的历史有分支,能看出来曾经做过合并
删除分支:git branch -d dev
查看分支合并图:git log –graph –pretty=oneline –abbrev-commit
11、git相关配置
安装完Git后第一件要做的事,设置用户信息(global可换成local在单独项目生效):
- git config –global user.name “用户名” # 设置用户名
- git config –global user.email “用户邮箱” #设置邮箱
- git config –global user.name # 查看用户名是否配置成功
- git config –global user.email # 查看邮箱是否配置
12、其他查看配置相关
- git config –global –list # 查看全局设置相关参数列表
- git config –local –list # 查看本地设置相关参数列表
- git config –system –list # 查看系统配置参数列表
- git config –list # 查看所有Git的配置(全局+本地+系统)
- git config –global color.ui true //显示git相关颜色
13、撤消某次提交
- git revert HEAD # 撤销最近的一个提交
- git revert 版本号 # 撤销某次commit
14、标签
- git tag 标签 //打标签命令,默认为HEAD
- git tag //显示所有标签
- git tag 标签 版本号 //给某个commit版本添加标签
- git show 标签 //显示某个标签的详细信息
11.npm指令
1、查看本地npm的版本:npm -v
2、升级npm版本:npm install npm@latest -g(@latest表示最新的版本)
3、查看指定命令的帮助:npm 指定命令 --help
4、查看npm帮助命令:npm --help
5、 初始化:npm init
6、初始化(跳过向导):npm init --yes(-y)
7、下载依赖:npm install
8、开发环境安装的包:npm install 包名 --save-dev(npm install 包名 -D)
9、开发/生产环境安装的包:npm install 包名 --save(npm install 包名 -S)
10、查看当前目录下已安装的 node 包:npm list(npm ls --depth=搜索的深度)
11、查看全局已经安装过的 node 包:npm list -g
12、更新指定包:npm update 包名
13、卸载指定包:npm uninstall 包名
14、查看配置信息:npm config list
15、查看远程npm上指定包的所有版本信息:npm info 指定包名
16、查看当前包的安装路径:npm root
17、查看全局的包的安装路径:npm root -g
18、查看本地安装的指定包及版本信息,没有显示 empty:npm ls 包名
19、查看全局安装的指定包及版本信息,没有显示 empty:npm ls 包名 -g
20、修改包下载源: npm config set registry 下载源
21、安装cnpm:npm install -g cnpm --registry=下载源
22、自动启动浏览器打开包的主页:npm home 包名
23、查看包现存的issue,或者公开的roadmap:npm bugs 包名
24、查看包的代码地址:npm repo 包名
25、查看包的详细信息:npm info 包名
26、搜索npm仓库:npm search 字符串/正则表达式
27、查看过时的依赖:npm outdated
28、执行脚本:npm run dev/build
29、清理、安装依赖项:npm ci
30、删除重复的依赖项:npm dedupe/ddp
31、扫描项目,来查找所有依赖项中存在的漏洞:npm audit
32、自动安装所有易受攻击包的补丁版本:npm audit fix
33、测试本地包:npm link/npm link 模块名/npm unlink 模块名
12.vite
- 为什么说 vite 比 webpack 要快
1.webpack:当一个文件变化时,会重新构建整个包文件,随着项目体积的增大,构建速度就会越来越慢
2.vite:当一个文件变化时,只需要构建相应的模块,无论项目体积多大,更新速度就很快
3.vite:合理利用浏览器的缓存来加速页面的更新。源码模块会根据 304 Not Modified进行协商缓存,依赖模块会根据Cache-Control: max-age=31536000,immutable 进行强缓存,因此一旦缓存,不会再次请求。
- vite和webpack优缺点对比e
优点:
- 更快的启动时间和更新速度
- 更好的开发体验:自动打开浏览器、自动刷新页面
- 配置简单。不需要过多的配置就可以搭建基本的开发环境
- 更少的依赖。借助原生的ES模块,避免了过多的额外依赖
缺点:
- vite的构建技术主要用于中小型项目,对于大型项目的支持不如webpack
- vite主要是针对vue3的单页面应用,对于多页面应用、ssr应用、自定义流程应用不如webpack
- 开发环境首屏加载慢,懒加载慢
- vite由于基于原生ES模块,不支持commonJs;webpack关注兼容性,vite关注浏览器端的开发体验,vite的生态还不如webpack
如何指定vite插件的执行顺序
enforce:pre | post | 默认
-
Alias
-
带有pre的用户插件
-
vite的核心插件
-
enforce=’默认’或者没有enforce字段的用户插件
-
vite构建用的插件
-
enforce=post的用户插件
-
vite的后置构建插件( 最小化、manifest、报告)
vite常见的hook函数
1.config:在解析vite配置前调用。用户可以通过这个hook修改config 2.configResolved:在解析vite配置后调用。可以在这个钩子函数里面获取解析完毕的config,不建议在这里面修稿config配置 3.configureServer:配置开发服务器的钩子,常用于dev server中添加中间件(middleware)
4.configurePreviewServer:和configureServer相似,只不过这是预览服务器
5.transformIndexHtml:转换index.html的专用钩子。可以返回 :转换后的html字符串;注入到现有HTML中的标签描述符对象数组{ tag, attrs, children };• 一个包含 {html, tags } 的对象 6.handleHotUpdate:执行自定义的热更新处理
- Vite是否支持 commonjs 写法
vite默认是不支持commonJs的写法的,因为vite利用浏览器原生的ES模块,只支持ES6的模块规范。可以在vite的配置文件中引入@vitejs/plugin-commonjs,这样就可以在vite中使用CommonJS 模块
13.继承方法
1 原型链继承
核心:让子类的原型指向父类的实例
ChildType.prototype = new ParentType()
// 所有涉及到原型链继承的继承方式都要修改子类构造函数的指向,否则子类实例的构造函数会指向PerentType。
ChildType.prototype.constructor =ChildType;
优点:父类方法可以复用
缺点:
- 父类的引用属性会被所有子类实例共享
- 子类构建实例时不能向父类传递参数
2 .构造函数继承
核心:将父类构造函数的内容复制给了子类的构造函数。这是所有继承中唯一一个不涉及到prototype的继承。
ParentType.call(ChildType);
优点:和原型链继承完全反过来。
- 父类的引用属性不会被共享
- 子类构建实例时可以向父类传递参数
缺点:父类的方法不能复用,子类实例的方法每次都是单独创建的。
3 .组合继承
核心:原型式继承和构造函数继承的组合,兼具了二者的优点。
function ParentType() {
this.name = 'parent';
this.arr = [1, 2, 3];
}
ParentType.prototype.say = function() { console.log('this is parent') }
function ChildType() {
ParentType.call(this)
// 第二次调用ParentType
}
ChildType.prototype = new ParentType() // 第一次调用ParentType
优点:
- 父类的方法可以被复用
- 父类的引用属性不会被共享
- 子类构建实例时可以向父类传递参数
缺点:
调用了两次父类的构造函数,第一次给子类的原型添加了父类的name, arr属性,第二次又给子类的构造函数添加了父类的name, arr属性,从而覆盖了子类原型中的同名参数。这种被覆盖的情况造成了性能上的浪费。
4 原型式继承
核心:原型式继承的object方法本质上是对参数对象的一个浅复制。
优点:父类方法可以复用
缺点:
- 父类的引用属性会被所有子类实例共享
- 子类构建实例时不能向父类传递参数 5 寄生式继承
核心:使用原型式继承获得一个目标对象的浅复制,然后增强这个浅复制的能力。
优缺点:仅提供一种思路,没什么优点
6 寄生组合继承
刚才说到组合继承有一个会两次调用父类的构造函数造成浪费的缺点,寄生组合继承就可以解决这个问题。 优缺点:这是一种完美的继承方式。
7:ES6 Class extends
核心: ES6继承的结果和寄生组合继承相似,本质上,ES6继承是一种语法糖。但是,寄生组合继承是先创建子类实例this对象,然后再对其增强;而ES6先将父类实例对象的属性和方法,加到this上面(所以必须先调用super方法),然后再用子类的构造函数修改this。
- ES6继承与ES5继承的异同:
相同点:本质上ES6继承是ES5继承的语法糖
不同点:
- ES6继承中子类的构造函数的原型链指向父类的构造函数,ES5中使用的是构造函数复制,没有原型链指向。
- ES6子类实例的构建,基于父类实例,ES5中不是。