目录
vue
1.vue2 和 vue3 的区别
2.vue2 和 vue3的原理
3.组合式api 和 选项式api
3. Proxy和object.defineproperty
4..v-show 与 v-if 的区别
5.计算属性和 watcher
6.虚拟DOM
7.key的作用是什么?
8.v-if 和 v-for 的优先级是什么?
9.vuex
JS
1.原型 原型链
2.你对闭包的理解?
3.内存泄漏
4.数组的常用方法有哪些?
5.Promise
6.什么是防抖和节流?有什么区别?如何实现?
7.谈谈 this 对象的理解
8.深拷贝与浅拷贝
9.箭头函数
10.reduce
css
1.css 新特性
2.BFC
3.说说你对盒子模型的理解?
4.块级元素和行内元素和行内块的区别
网络相关
1.什么是 HTTP? HTTP 和 HTTPS 的区别?
2.三次握手和四次挥手
3.Vue 项目中你是如何解决跨域的呢?
1.更容易维护
更好的组合式api , vue2是选项式 更好的的ts支持
Vue 3引入了组合式API,使得代码组织更加灵活和可维护。Vue 2中使用的Options API虽然简单易用,但对于大型项目来说,组织和复用代码变得困难。组合式API允许我们根据逻辑相关性组织代码,提供了更好的封装性和代码复用性。
2.更快的速度
重写diff算法
3.更小的提交 按需引入
Vue 3在体积上进行了优化,使得打包后的文件更小。通过移除了一些不常用的特性、使用了更好的树摇(Tree Shaking)和代码压缩算法,Vue 3的体积相比Vue 2更小,加载速度更快
4.更优的数据响应式
proxy , 相较于Vue 2的Object.defineProperty,性能更好。
1.vue2通过object.definedProperty()的get()和set()来做数据劫持、结合发布订阅者模式来实现,Object.definedProperty()会遍历每一个属性。
2.vue3通过proxy代理的方式实现。
3.proxy的优势:不需要像object,definedProperty()的那样遍历每一个属性,有一定的性能提升proxy,可以理解为在目标对象之前架设一层“拦藏”,外界对该对象的访问都必须通过这一层拦藏。这个拦藏可以对外界的访问进行过滤和改写。
4.当属性过多的时候利用Object.definedProperty(O要通过遍历的方式监听每一个属性。利用proxy则不需要遍历,会自动监听所有属性,有利于性能的提升
vue2 通过 data、methods、watch , 只能定义一个 是选项式API写法
组合式是 vue3 中的 所有逻辑在setup函数中 ,通过ref 定义
组合式的好处有:可复用,可维护
组合式api更加有利于: 逻辑复用, v2中使用mixins来做 , 但是mixins会产生命名冲突和数据来源不明确等问题
在项目开发中,有两个功能特别类似,如果单独实现,会有很多重复的代码
在v3中,我们利用组合式api的特点,他们抽象出来,进行封装,把得到函数写在一个单独的模块中,导出,以供复用
Object.defineProperty只能遍历对象属性进行劫持
Proxy直接可以劫持整个对象,并返回一个新对象,我们可以只操作新的对象达到响应式目的
Proxy可以直接监听数组的变化(push、shift、splice)
Proxy有多达 13 种拦截方法,不限于apply、ownKeys、deleteProperty、has等等,这是Object.defineProperty不具备的
正因为defineProperty自身的缺陷,导致Vue2在实现响应式过程需要实现其他的方法辅助(如重写数组方法、增加额外set、delete方法)
Proxy 不兼容 IE,也没有 polyfill, defineProperty 能支持到 IE9
控制手段:v-show
隐藏则是为该元素添加css--display:none
,元素依旧还在。v-if
显示隐藏是将元素整个添加或删除
编译过程:v-if
切换有一个局部编译/卸载的过程,切换过程中合适地销毁和重建内部的事件监听和子组件;v-show
只是简单的基于 css 切换
编译条件:v-if
是真正的条件渲染,它会确保在切换过程中条件块内的事件监听器和子组件适当地被销毁和重建。只有渲染条件为假时,并不做操作,直到为真才渲染
v-show
由false
变为true
的时候不会触发组件的生命周期
v-if
由false
变为true
的时候,触发组件的beforeCreate
、create
、beforeMount
、mounted
钩子,由true
变为false
的时候触发组件的beforeDestory
、destoryed
方法
性能消耗:v-if
有更高的切换消耗;v-show
有更高的初始渲染消耗;
答: 区别: watch 侦听某一数据的变化从而会触发函数,当数据为对象类型时,对象中的属性值变化时需要使用深度侦听 deep 属性,也可在页面第一次加载时使用立即侦听 immdiate 属性 computed 计算属性是触发函数内部任一依赖项的变化都会重新执行该函数,计算属性有缓存,多次重复使用计算属性时会从缓存中获取返回值,计算属性必须要有 return 关键词
vue 中的 watcher 有三类
computed 是一种特殊的 watcher
watch 和 computed 都是以函数为基础的,它们都是通过监听自身依赖的数据在变化时触发相关的函数去实现自身数据的变动。
不同点
运行时机不同
1.computed 是在 HTML,DOM 加载后马上执行的,如赋值;(属性将被混入到 Vue 实例)
2.watch 它用于观察 Vue 实例上的数据变动,一般情况下是依赖项的值变化之后再执行,当然可以设置立刻执行
虚拟dom相对于真实DOM而言的,在react,vue等技术出现之前,我们要改变页面展示的内容只能通过遍历查询 dom 树的方式找到需要修改的 dom 然后修改样式行为或者结构,来达到更新 ui 的目的。
这种方式相当消耗计算资源,因为每次查询 dom 几乎都需要遍历整颗 dom 树,如果建立一个与 dom 树对应的虚拟 dom 对象( js 对象),以对象嵌套的方式来表示 dom 树及其层级结构,那么每次 dom 的更改就变成了对 js 对象的属性的增删改查,这样一来查找 js 对象的属性变化要比查询 dom 树的性能开销小。
页面上的标签都对应具体的虚拟 dom 对象(虚拟 dom 就是 js 对象), 循环中 ,如果没有唯一 key , 页面上删除一条标签, 由于并不知道删除的是那一条! 所以要把全部虚拟 dom 重新渲染, 如果知道 key 为对应标签被删除掉, 只需要把渲染的 dom 为对应标签去掉即可!key 是给每一个 vnode 的唯一 id,也是 diff 的一种优化策略,可以根据 key,更准确, 更快的找到对应的 vnode 节。
作用:更准确、更快速、提高效率
v-if 不能和 v-for 一起使用的原因是 v-for 的优先级比 v-if 高,先循环再做分支判断,一起使用会造成性能浪费 解决方案有两种:
把 v-if 放在 v-for 的外层
把需要 v-for 的值先在计算属性中过滤一次
最终结论:
v2 中:v-for
优先级比v-if
高
v3 中:v-if
优先级比v-for
高
使用过程中,不要把它们同时用在一个元素上。
vuex 中有六个主要的成员:
闭包是一个可以访问其他函数内部变量的函数,主要作用是解决变量污染问题,也可以用来延长局部变量的生命周期。闭包在 js 中使用比较多,几乎是无处不在的。一般大多数情况下,在回调函数中闭包用的是最多的。闭包可能会造成内存泄漏
内存泄漏一般是指变量的内存没有及时的回收,导致内存资源浪费。一般有三种情况出现内存泄露比较多。(1)常见的声明了一个全局变量,但是又没有用上,那么就有点浪费内存了,(2)定时器没清除 (3)循环引用:A 对象里面有一个属性指向 B 对象,B 对象有一个属性指向 A 对象。互相引用
解决内存泄露:我们编译器有一个自动的内存清理。常见的主要是引用记数 和 标记清除。 谷歌浏览器主要是用标记清除,大概流程是给每一个变量添加一个标记,通过内部算法计算引用情况,当不使用的时候就会自动清除。如果遇到定时器的话,我一般会在页面关闭的时候手动清除。如果遇到循环引用,我一般会手动把变量赋值为 null 来清除
数组的方法有很多,大概分为以下几类
Promise 是异步编程的一种解决方案,它是一个对象,可以获取异步操作的消息,他的出现一定程度上解决了异步编程中回调地狱的问题,它比传统的解决方案回调函数和事件更合理和更强大。
所谓 Promise,简单说就是一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果。从语法上说,Promise 是一个对象,从它可以获取异步操作的消息。Promise 提供统一的 API,各种异步操作都可以用同样的方法进行处理。
三种状态
pending
(进行中)fulfilled
(或者resolved, 已成功)rejected
(已失败)promise 的状态改变是不可逆的
promise 的常见 API
返回一个新的 promise 对象
为啥可以链式调用?
链式调用就是用.语法持续去调用示例方法,例如: Promise.then().then().catch().finally().catch().then()
之所以可以链式调用的原因是这些示例方法的返回值仍是一个promise对象,所以可以持续的链式调用。值得注意的是finally()的返回值仍是一个Promise对象,它也可以继续链式调用
防抖和节流是性能优化手段
什么是防抖? 防抖:单位时间内,频繁触发事件,只执行最后一次。 防抖的主要应用场景:
什么是节流? 节流:单位时间内,频繁触发事件,只执行一次。 节流的主要应用场景:
相同点:
不同点:
在绝大多数情况下,函数的调用方式决定了 this 对象的指向
this 关键字是函数运行时自动生成的一个内部对象,只能在函数内部使用,总指向调用它的对象
根据不同的使用场合,this 对象有不同的指向,主要分为下面几种情况
默认绑定
隐式绑定
函数还可以作为某个对象的方法调用,这时 this 就指这个上级对象
new 绑定
显示绑定
箭头函数
箭头函数没有自己的 this 值,箭头函数中所使用的 this 来自于函数作用域链
箭头函数没有自己的 this 值,箭头函数中所使用的 this 都是来自函数作用域链,它的取值遵循普通普通变量一样的规则,在函数作用域链中一层一层往上找。
浅拷贝是拷贝一层,属性为对象时,浅拷贝是复制,两个对象指向同一个地址。实际开发常用的方法有:object.assgin,扩展运算符(...) ,Array.prototype.slice()
, Array.prototype.concat()
等等。
深拷贝是递归拷贝深层次,属性为对象时,深拷贝是新开栈,两个对象指向不同的地址。开发中常用的方法有: (1) loadsh 中的_.cloneDeep()
方法 (2)JSON.stringify() JSON.parse()
。缺点是会忽略undefined
、symbol
和函数
9.
箭头函数箭头函数是ES6提出了的新语法。它最大的意义是解放了Function的功能。 在js中,Function是一等公民,它不但承担了本质的函数的功能,还可以做构造函数来使用,现在有了箭头函数,其实大大简化了Function的使用频率。
与普通函数相比,他:
我现在在写v3的代码,所以使用箭头函数还是比较多的。
reduce 作用:给每一个元素执行一次回调函数,并且返回最终的结果
reduce 参数有两个:第一个是回调函数,第二个是初始值。 一般初始值都会设置为 0,目的是避免空数组报错
reduce 方法的返回值:就是执行完遍历之后,最终的累加值
C3 的新特性有很多,常见的如下:
BFC 的中文意思是块级格式化上下文,是用于布局块级盒子的独立渲染区域,一个创建了新的 BFC 的盒子是独立布局的,盒子内元素的布局 不会影响盒子外面的元素。
简单来说就是 BFC 就是 css 的一个布局概念,是一个独立的区域(容器)
满足下列条件之一就可以触发 BFC:
可以解决什么问题:margin 重叠,清除浮动,自适应布局.
参考文章:https://juejin.cn/post/6950082193632788493
盒子模型组成有 4 部分,分别为:内容 内边距 外边距(一般不计入盒子实际宽度) 边框
盒子模型有 2 种:标准盒子模型与怪异盒子模型
标准盒子模型=content(内容)+border(边框)+padding(内边距)
怪异盒子模型=content(内容)(已经包含了 padding 和 border)
css3 种可以通过设置 box-sizing 属性来完成标准或许怪异盒子模型之间的切换,怪异盒子模型:box-sizing: border-box;标准盒子模型:box-sizing:content-box
通过设置 display 属性可以改变元素的类型。
1.块级元素(block)的特点
常见的有:div, h1, p
2.inline元素的特点
常见的有:i span a
3.inline-block元素的特点
常见的有:buttton img, input
http 是无状态的超文本传输协议,连接简单,信息是明文传输,端口为 80。
https 协议是由 http+ss 协议构建的可进行加密传输、身份认证的具有安全性网络协议,端口是 443
优缺点
https 有加密认证相对于 http 安全一些
https 因为需要进行加密解密等过程,因此速度会更慢;
三次握手是为了确认双方的接收与发送能力是否正常。
1、第一次握手:客户端给服务器发送一个 SYN 报文。
2、第二次握手:服务器收到 SYN 报文之后,会应答一个 SYN+ACK 报文。
3、第三次握手:客户端收到 SYN+ACK 报文之后,会回应一个 ACK 报文。 服务器收到 ACK 报文之后,三次握手建立完成。
当客户端和服务端通过三次握手建立 TCP 连接进行可靠数据传输后,当数据传送完毕,肯定是要断开 TCP 连接,所以就有了四次挥手。
四次挥手是为了断开连接后「资源」正常释放,双方都可以主动断开连接。
1、第一次挥手:客户端发送一个 FIN 报文,报文中会指定一个序列号。此时客户端处于 FIN_WAIT1 状态。
2、第二次握手:服务端收到 FIN 之后,会发送 ACK 报文,且把客户端的序列号值 + 1 作为 ACK 报文的序列号值,表明已经收到客户端的报文了,此时服务端处于 CLOSE_WAIT 状态。
3、第三次挥手:如果服务端也想断开连接了,和客户端的第一次挥手一样,发给 FIN 报文,且指定一个序列号。此时服务端处于 LAST_ACK 的状态。
4、第四次挥手:客户端收到 FIN 之后,一样发送一个 ACK 报文作为应答,且把服务端的序列号值 + 1 作为自己 ACK 报文的序列号值,此时客户端处于 TIME_WAIT 状态。需要过一阵子以确保服务端收到自己的 ACK 报文之后才会进入 CLOSED 状态
5、服务端收到 ACK 报文之后,就处于关闭连接了,处于 CLOSED 状态
扩展
为什么只有三次握手才能确认双方的接受与发送能力是否正常,而两次却不可以:
第一次握手:客户端发送网络包,服务端收到了。这样服务端就能得出结论:客户端的发送能力、服务端的接收能力是正常的。
第二次握手:服务端发包,客户端收到了。这样客户端就能得出结论:服务端的接收、发送能力,客户端的接收、发送能力是正常的。不过此时服务器并不能确认客户端的接收能力是否正常。
第三次握手:客户端发包,服务端收到了。这样服务端就能得出结论:客户端的接收、发送能力正常,服务器自己的发送、接收能力也正常。
因此,需要三次握手才能确认双方的接收与发送能力是否正常。
跨域,是指在浏览器中a页面去请求了b页面的资源,更具体的来说是指a页面和b页面的:协议,主机,端口这三个有一个不同,就是跨域请求。
这种情况在网页开发中是非常常见的。但是,对于特殊的ajax请求,出于安全性的考虑,浏览器对跨域的ajax请求做了限制。
跨域的请求不一定报错(例如:script, css等等), ajax请求才会报错。
常见的解决方案有 3 种: