VUE面试题汇总(一)
1. vue 中的性能优化参考答案:1)编码优化尽量减少data中的数据,data中的数据都会增加getter和setter,会收集对应的watcherv-if和v-for不能连用如果需要使用v-for给每项元素绑定事件时使用事件代理SPA 页面采用keep-alive缓存组件在更多的情况下,使用v-if替代v-showkey保证唯一使用路由懒加载、异步组件防抖、节流第三方模块按需导入长列表滚动到
1. vue 中的性能优化
参考答案:
1)编码优化
- 尽量减少data中的数据,data中的数据都会增加getter和setter,会收集对应的watcher
- v-if和v-for不能连用
- 如果需要使用v-for给每项元素绑定事件时使用事件代理
- SPA 页面采用keep-alive缓存组件
- 在更多的情况下,使用v-if替代v-show
- key保证唯一
- 使用路由懒加载、异步组件
- 防抖、节流
- 第三方模块按需导入
- 长列表滚动到可视区域动态加载
- 图片懒加载
2)用户体验优化
- 骨架屏
- PWA(渐进式WEB应用)
- 还可以使用缓存(客户端缓存、服务端缓存)优化、服务端开启gzip压缩等。
3)SEO优化
- 预渲染
- 服务端渲染SSR
4)打包优化
- 压缩代码;
- Tree Shaking/Scope Hoisting;
- 使用cdn加载第三方模块;
- 多线程打包happypack;
- splitChunks抽离公共文件;
- sourceMap优化;
说明:优化是个大工程,会涉及很多方面
2. Vue 的实例生命周期
参考答案:
(1) beforeCreate 初始化实例后 数据观测和事件配置之前调用
(2) created 实例创建完成后调用
(3) beforeMount 挂载开始前被用
(4) mounted el 被新建 vm. $el 替换并挂在到实例上之后调用
(5) beforeUpdate 数据更新时调用
(6) updated 数据更改导致的 DOM 重新渲染后调用
(7) beforeDestory 实例被销毁前调用
(8) destroyed 实例销毁后调用
Vue2 与Vue3的生命周期对比
变量 | 实例化(次数) |
---|---|
beforeCreate(组件创建之前) | setup(组件创建之前) |
created(组件创建完成) | setup(组件创建完成) |
beforeMount(组件挂载之前) | onBeforeMount(组件挂载之前) |
mounted(组件挂载完成) | onMounted(组件挂载完成) |
beforeUpdate(数据更新,虚拟DOM打补丁之前) | onBeforeUpdate(数据更新,虚拟DOM打补丁之前) |
updated(数据更新,虚拟DOM渲染完成) | onUpdated(数据更新,虚拟DOM渲染完成) |
beforeDestroy(组件销毁之前) | onBeforeUnmount(组件销毁之前) |
destroyed(组件销毁之后) | onUnmounted(组件销毁之后) |
3. Vue 的双向数据绑定的原理
参考答案:
VUE 实现双向数据绑定的原理就是利用了 Object. defineProperty() 这个方法重新定义了对象获取属性值(get)和设置属性值(set)的操作来实现的。
Vue3. 0 将用原生 Proxy 替换 Object. defineProperty
4. 为什么要替换 Object. defineProperty?(Proxy 相比于 defineProperty 的优势)
参考答案:
-
在 Vue 中,Object.defineProperty 无法监控到数组下标的变化,导致直接通过数组的下标给数组设置值,不能实时响应。
-
Object.defineProperty只能劫持对象的属性,因此我们需要对每个对象的每个属性进行遍历。Vue 2.x里,是通过 递归 + 遍历 data 对象来实现对数据的监控的,如果属性值也是对象那么需要深度遍历,显然如果能劫持一个完整的对象是才是更好的选择。
而要取代它的Proxy有以下两个优点;
- 可以劫持整个对象,并返回一个新对象
- 有13种劫持操作
既然Proxy能解决以上两个问题,而且Proxy作为es6的新属性在vue2. x之前就有了,为什么vue2. x不使用Proxy呢?一个很重要的原因就是:
Proxy是es6提供的新特性,兼容性不好,最主要的是这个属性无法用polyfill来兼容
5. 什么是 Proxy?
参考答案:
- 含义:
Proxy 是 ES6 中新增的一个特性,翻译过来意思是"代理",用在这里表示由它来“代理”某些操作。 Proxy 让我们能够以简洁易懂的方式控制外部对对象的访问。其功能非常类似于设计模式中的代理模式。
Proxy 可以理解成,在目标对象之前架设一层“拦截”,外界对该对象的访问,都必须先通过这层拦截,因此提供了一种机制,可以对外界的访问进行过滤和改写。
使用 Proxy 的核心优点是可以交由它来处理一些非核心逻辑(如:读取或设置对象的某些属性前记录日志;设置对象的某些属性值前,需要验证;某些属性的访问控制等)。 从而可以让对象只需关注于核心逻辑,达到关注点分离,降低对象复杂度等目的。
- 基本用法:
let p = new Proxy(target, handler);
参数:
- target 是用Proxy包装的被代理对象(可以是任何类型的对象,包括原生数组,函数,甚至另一个代理)。
- handler 是一个对象,其声明了代理target 的一些操作,其属性是当执行一个操作时定义代理的行为的函数。
- p 是代理后的对象。当外界每次对 p 进行操作时,就会执行 handler 对象上的一些方法。Proxy共有13种劫持操作,handler代理的一些常用的方法有如下几个:
get: 读取
set: 修改
has: 判断对象是否有该属性
construct: 构造函数
- 示例:
下面就用Proxy来定义一个对象的get和set,作为一个基础demo
let obj = {};
let handler = {
get(target, property) {
console.log( `${property} 被读取` );
return property in target ? target[property] : 3;
},
set(target, property, value) {
console.log( `${property} 被设置为 ${value}` );
target[property] = value;
}
}
let p = new Proxy(obj, handler);
p.name = 'tom' //name 被设置为 tom
p.age; //age 被读取 3
p 读取属性的值时,实际上执行的是 handler. get() :在控制台输出信息,并且读取被代理对象 obj 的属性。
p 设置属性值时,实际上执行的是 handler. set() :在控制台输出信息,并且设置被代理对象 obj 的属性的值。
以上介绍了Proxy基本用法,实际上这个属性还有许多内容,具体可参考Proxy文档
6. 为什么避免 v-if 和 v-for 用在一起
参考答案:
vue2.x 中v-for优先级高于v-if,vue3.x 相反。所以2.x 版本中在一个元素上同时使用 v-if 和 v-for 时,v-for 会优先作用,造成性能浪费;3.x 版本中 v-if 总是优先于 v-for 生效,导致v-if访问不了v-for中的变量。
解析:
一般我们在两种常见的情况下会倾向于这样做:
-
为了过滤一个列表中的项目 (比如 v-for=“user in users” v-if=“user.isActive”)。在这种情形下,请将 users 替换为一个计算属性 (比如 activeUsers),让其返回过滤后的列表。
-
为了避免渲染本应该被隐藏的列表 (比如 v-for=“user in users” v-if=“shouldShowUsers”)。这种情形下,请将 v-if 移动至容器元素上 (比如 ul、ol)。
当 Vue 处理指令时,v-for 比 v-if 具有更高的优先级,所以这个模板:
<ul>
<li
v-for="user in users"
v-if="user.isActive"
:key="user.id"
>
{{ user.name }}
</li>
</ul>
将会经过如下运算:
this.users.map(function (user) {
if (user.isActive) {
return user.name
}
})
因此哪怕我们只渲染出一小部分用户的元素,也得在每次重渲染的时候遍历整个列表,不论活跃用户是否发生了变化。
通过将其更换为在如下的一个计算属性上遍历:
computed: {
activeUsers: function () {
return this.users.filter(function (user) {
return user.isActive
})
}
}
<ul>
<li
v-for="user in activeUsers"
:key="user.id"
>
{{ user.name }}
</li>
</ul>
我们将会获得如下好处:
- 过滤后的列表只会在 users 数组发生相关变化时才被重新运算,过滤更高效。
- 使用 v-for=“user in activeUsers” 之后,我们在渲染的时候只遍历活跃用户,渲染更高效。
- 解耦渲染层的逻辑,可维护性 (对逻辑的更改和扩展) 更强。
为了获得同样的好处,我们也可以把:
<ul>
<li
v-for="user in users"
v-if="shouldShowUsers"
:key="user.id"
>
{{ user.name }}
</li>
</ul>
更新为:
<ul v-if="shouldShowUsers">
<li
v-for="user in users"
:key="user.id"
>
{{ user.name }}
</li>
</ul>
通过将 v-if 移动到容器元素,我们不会再对列表中的每个用户检查 shouldShowUsers。取而代之的是,我们只检查它一次,且不会在 shouldShowUsers 为否的时候运算 v-for。
反例:
<ul>
<li
v-for="user in users"
v-if="user.isActive"
:key="user.id"
>
{{ user.name }}
</li>
</ul>
<ul>
<li
v-for="user in users"
v-if="shouldShowUsers"
:key="user.id"
>
{{ user.name }}
</li>
</ul>
好例子
<ul>
<li
v-for="user in activeUsers"
:key="user.id"
>
{{ user.name }}
</li>
</ul>
<ul v-if="shouldShowUsers">
<li
v-for="user in users"
:key="user.id"
>
{{ user.name }}
</li>
</ul>
7. 组件的设计原则
参考答案:
(1)页面上每个独立的可视/可交互区域视为一个组件(比如页面的头部,尾部,可复用的区块)
(2)每个组件对应一个工程目录,组件所需要的各种资源在这个目录下就近维护(组件的就近维护思想体现了前端的工程化思想,为前端开发提供了很好的分治策略,在vue.js中,通过.vue文件将组件依赖的模板,js,样式写在一个文件中)
(每个开发者清楚开发维护的功能单元,它的代码必然存在在对应的组件目录中,在该目录下,可以找到功能单元所有的内部逻辑)
(3)页面不过是组件的容器,组件可以嵌套自由组合成完整的页面
8. vue slot是做什么的?
参考答案:主要是让组件的可扩展性更强,简单点说就是,能够在组件内写其他内容
解析:
插槽
在 2.6.0 中,我们为具名插槽和作用域插槽引入了一个新的统一的语法 (即 v-slot 指令)。它取代了 slot 和 slot-scope 这两个目前已被废弃但未被移除且仍在文档中的 attribute。
插槽内容
Vue 实现了一套内容分发的 API,这套 API 的设计灵感源自 Web Components 规范草案,将 元素作为承载分发内容的出口。
它允许你像这样合成组件:
<navigation-link url="/profile">
Your Profile
</navigation-link>
然后你在 的模板中可能会写为:
<a
v-bind:href="url"
class="nav-link"
>
<slot></slot>
</a>
编译作用域
9. 对于 Vue 是一套渐进式框架的理解
参考答案:
渐进式代表的含义是:没有多做职责之外的事。
vue.js只提供了vue-cli生态中最核心的组件系统和双向数据绑定,像vuex、vue-router都属于围绕vue.js开发的库。
解析:
要使用Angular,必须接受以下东西:
1、必须使用它的模块机制。
2、必须使用它的依赖注入。
3、必须使用它的特殊形式定义组件(这一点每个视图框架都有,这是难以避免的)
所以Angular是带有比较强的排它性的,如果你的应用不是从头开始,而是要不断考虑是否跟其他东西集成,这些主张会带来一些困扰。
要使用React,你必须理解:
1、函数式编程的理念。
2、需要知道它的副作用。
3、什么是纯函数。
4、如何隔离、避免副作用。
5、它的侵入性看似没有Angular那么强,主要因为它是属于软性侵入的。
Vue与React、Angular的不同是,它是渐进的:
1、可以在原有的大系统的上面,把一两个组件改用它实现,就是当成jQuery来使用。
2、可以整个用它全家桶开发,当Angular来使用。
3、可以用它的视图,搭配你自己设计的整个下层使用。
4、可以在底层数据逻辑的地方用OO(Object–Oriented)面向对象和设计模式的那套理念。
5、可以函数式,它只是个轻量视图而已,只做了最核心的东西。
场景联想
场景 1:
维护一个老项目管理后台,日常就是提交各种表单了,这时候你可以把 vue 当成一个 js 库来使用,就用来收集 form 表单,和表单验证。
场景 2:
得到 boss 认可,后面整个页面的 dom 用 Vue 来管理,抽组件,列表用 v-for 来循环,用数据驱动 DOM 的变化
场景 3:
越来越受大家信赖,领导又找你了,让你去做一个移动端 webapp,直接上了 vue 全家桶!
场景 1-3 从最初的只因多看你一眼而用了前端 js 库,一直到最后的大型项目解决方案。
10. vue. js 的两个核心是什么?
参考答案:
数据驱动和组件化思想
更多推荐
所有评论(0)