1. 前端项目中遇到什么困难?是怎么解决的?
答:在前端项目中,用户完成登陆之后,页面一刷新就会退出登陆。检测问题,是用户数据没有持久化保存。 项目中使用的是Pinia,利用Pinia管理用户状态。Pinia中,创建了一个用户数据store,检测其中的代码和逻辑,发现没有错误;检查登陆接口的api,因为初始状态是能够登陆页面的,因此api这里没有问题;检测main.js中的持久化插件的注册,发现问题。在main.js中引入依赖之后,创建了Pinia实例,并调用use方法注册piniaPluginPersistedstate插件,使用app.use(pinia),将pinia实例添加到vue应用实例的插件列表中。后面又创建了一个pinia实例,相当于后面的pinia覆盖了前面的pinia。
2. Vue3和Vue2的区别
答:1)性能上的改进。Vue3使用proxy API来提高性能,使用静态树提升提高渲染性能。
2)组合式API:VUE3中组合式的api会使得代码更加模块化和可复用,提供更好ts支持,包括更好的类型推断 和更好的类型定义
3)Vue3中有着更小的代码体积,更易于使用和部署。
3. vue2 中的双向数据绑定原理
答:vue是通过数据劫持结合发布者-订阅者模式的方法,通过Object.defineProperty()来劫持各个属性的setter和getter,在数据变动时发布消息给订阅者,触发相应的监听回调来渲染视图。
-
数据劫持的定义
在访问或者修改对象的属性时,对这些操作进行拦截和监视,以便在属性发生变化的时候能够触发相关的操作。Vue中数据劫持用于监听数据的变化,实现双向绑定和响应式的更新。
-
怎么实现数据劫持?
Vue通过在数据对象的属性上使用Object.defineProperty实现的数据劫持,每当访问属性或者修改属性的时候,Vue会触发相应的get和set拦截器
Object.defineProperty是js提供的一个方法,可以直接在一个对象上定义一个属性或者修改一个对象的现有属性,返回这个对象。
Object.definePropert(obj, property name,属性描述Property Descriptor)
属性描述对象:
alue:属性的值(默认为 undefined)。
writable:属性是否可写(默认为 false)。
enumerable:属性是否可枚举(使用for...in或Object.keys())(默认为 false)。
configurable:属性是否可配置(默认为 false),是否可以删除目标属性或是否可以再次修改属性的特性(writable, configurable, enumerable)。
get:获取属性值的函数。当访问该属性时,该方法会被执行。函数的返回值会作为该属性的值返回。
set:设置属性值的函数。当属性值修改时,该方法会被执行。该方法将接受唯一参数,即该属性新的参数值。
注意:
当使用了getter或setter方法,不允许使用writable和value这两个属性;
不要在getter中再次获取该属性值,也不要在setter中再次设置该属性,否则会栈溢出。
4. vue v-if 和 v-for 的优先级
-
Vue2:当v-if与v-for一起使用时,v-for具有比 v-if更高的优先级;
v-if: 根据表达式的值切换元素,在切换元素的时候,涉及到的数据或者组件会被销毁或者重建。
-
Vue3:当 v-if 与 v-for 一起使用时,v-if 具有比 v-for 更高的优先级。
V-if的优先级高,说明v-if不能使用v-for的数据
5. vue 中异步请求适合在那个生命周期中调用
生命周期:从开始创建、初始化数据、编译模版、挂载Dom -> 渲染、更新 -> 渲染、卸载等一系列过程,是Vue的生命周期。
官方实例的异步请求是在mounted生命周期中调用的,而实际上也可以在created生命周期中调用。
6. js中for in和for of的区别
for of 是新增的遍历方式,允许遍历一个含有iterator接口的数据结构(数组、对象等)并且返回各项的值;for in
区别
- for of 获取对象的键值,for in 获取对象的键名
- for in 遍历对象的整个原型链,性能较差;for of 只会遍历当前对象,而不是原型链。
- for in会返回数组中所有可枚举的属性,for of 只返回数组下标对应的属性值。
总结:
for...in 循环主要是为了遍历对象而生,不适用于遍历数组;for...of 循环可以用来遍历数组、类数组对象,字符串、Set、Map 以及 Generator 对象。
7. js中 深拷贝和浅拷贝的区别,以及如何实现?
浅拷贝
如果属性是基本类型,拷贝的就是基本类型的值,如果属性是引用对象,那么拷贝的就是内存地址(此时就是新旧对象共享同一个内存)。修改其中一个对象就会改变另外一个对象。浅拷贝就是拷贝了指针,使得两个指针指向的是同一个地址,这样在对象块结束,调用函数析构的时,会造成同一份资源析构2次,即delete同一块内存2次,造成程序崩溃)
深拷贝
深拷贝就是将一个对象从内存中完整的拷贝一份出来,从堆内存中开辟一个新的区域来存放新对象
8. css 中隐藏元素的方法和区别
- display:none: 渲染树不包含这个渲染对象,因此这个元素不会在页面中占据位置,不影响响应绑定的监听事件。
- opcity:0:* 这里是将元素的透明度设置为0,实现对元素的隐藏,但是元素其实还是在页面中的,能够影响元素绑定的监听事件。
- z-index:-1:使用其他的元素遮盖这个元素,实现隐藏。
- visibility:hidden:元素还是在页面中的,而且还占据空间,但是不会影响绑定的监听事件。
- position:absolute:通过使用绝对定位的方法将元素移除可视区域内,实现元素的隐藏。
- transform:scale(0,0):通过将元素缩放为0,实现元素的隐藏。元素还是页面中,但是不会响应绑定的监听事件。
9. 事件循环
- JS事件驱动模型的核心是事件循环。 事件循环就是一个不断循环的过程,JS引擎会检查宏队列和微队列里的任务有没有被处理完,如果宏队列和微队列均为空,则JS引擎会一直休眠,等待宏队列和微队列中被新加入的任务唤醒。其中, 宏任务存放在宏任务队列中,常见的宏任务有setTimeout、setInterval、setImmediate和I/O操作等。而微任务则处于微任务队列中,常见的微任务有Promise.then、process.nextTick和object.observe,主要用于对象数据的监听。
- NodeJS 和浏览器的设计都是基于事件驱动的,简而言之就是由特定的事件来触发特定的任务,这里的事件可以是用户的操作触发的,如 click 事件;也可以是程序自动触发的,比如浏览器中定时器线程在计时结束后会触发定时器事件。
事件循环
JS 在解析一段代码时,会将同步代码按顺序排在某个地方,即执行栈,然后依次执行里面的函数。当遇到异步任务时就交给其他线程处理,待当前执行栈所有同步代码执行完成后,会从一个队列中去取出已完成的异步任务的回调加入执行栈继续执行,遇到异步任务时又交给其他线程,…,如此循环往复。而其他异步任务完成后,将回调放入任务队列中待执行栈来取出执行。
JS 按顺序执行执行栈中的方法,每次执行一个方法时,会为这个方法生成独有的执行环境(上下文 context),待这个方法执行完成后,销毁当前的执行环境,并从栈中弹出此方法(即消费完成),然后继续下一个方法。