Vue面试八股文二
关于自定义指令
自定义指令是一种在 Vue.js 中扩展 HTML 元素功能的方式。它们可以让你在 Vue.js 应用程序中创建自己的指令,以便在 HTML 元素上添加自定义的行为和功能。
自定义指令中的钩子函数可以让你在不同的阶段对指令进行处理:
bind
:在指令绑定到元素上时调用,只调用一次。这个函数可以用来初始化指令的一些状态,例如设置元素的初始样式或属性。inserted
:在元素插入到 DOM 中时调用。这个函数可以用来执行一些与 DOM 相关的操作,例如聚焦到元素上或添加事件监听器。update
:在元素的 VNode 更新时调用,可能会被调用多次。这个函数可以用来根据指令的值更新元素的样式或属性。componentUpdated
:在元素的 VNode 及其子 VNode 全部更新后调用。这个函数可以用来执行一些需要在所有子元素都更新后才能执行的操作。unbind
:在指令从元素上解绑时调用,只调用一次。这个函数可以用来清理指令占用的资源,例如移除事件监听器或清除定时器。
//在main.js中
Vue.directive('xxx', { // xxx 是指令名, v-xxx 使用
inserted(el,binding) { // inserted 是DOM元素创建时执行的回调函数
el.style.color='red'
},
update (el, binding) { // update 是元素更新时执行的回调函数
el.style.color = binding.value
}
})
el
:表示绑定了指令的 DOM 元素binding
:一个对象,包含了指令的一些信息,例如指令的名称、值、表达式等
mockjs 是什么?mockjs 怎样模拟数据?模拟出来的数据是动态还是静态的?
Mock.js
是一个用于生成模拟数据的 JavaScript 库。它可以帮助前端开发人员在没有真实数据的情况下,快速生成模拟数据,以便进行开发和测试。
Mock.js
提供了一种简单的方式来定义数据模板,然后根据模板生成随机数据。它支持多种数据类型,如字符串、数字、布尔值、日期、数组、对象等,并且可以自定义数据的格式和范围。
使用Mock.js
可以带来以下好处:
- 提高开发效率:在开发过程中,不需要等待后端提供真实数据,可以使用
Mock.js
生成模拟数据,从而加快开发速度。 - 独立开发和测试:前端开发人员可以独立于后端进行开发和测试,不受后端接口的限制。
- 模拟真实数据:
Mock.js
可以生成符合真实数据格式和范围的模拟数据,从而更好地模拟真实场景,提高测试的准确性。 - 易于使用:
Mock.js
提供了简单易懂的 API,使用起来非常方便
// 引入Mock.js库
import Mock from 'mockjs';
// 定义数据模板
const template = {
'name': '@cname',
'age': '@integer(18, 60)',
'email': '@email'
};
// 生成模拟数据
const data = Mock.mock(template);
console.log(data);
选项式 API 和组合式 API 有何不同?
在性能方面,选项式 API 和组合式 API 并没有太大的区别。但是,由于组合式 API 提供了更好的代码组织方式和逻辑复用方式,能够让开发者更加容易地写出高性能的代码。
代码组织:
- 选项式 API 将组件的逻辑按照不同的功能进行分类,分别放在不同的选项中,比如
data
、methods
、computed
、watch
等。这种方式的优点是代码结构清晰,易于理解和维护。但是,当组件的逻辑变得复杂时,选项式 API 可能会导致代码变得冗长和难以维护。 - 组合式 API 将组件的逻辑拆分成不同的函数,这些函数可以在组件中自由组合和复用。这种方式的优点是代码更加灵活和可复用,能够更好地适应复杂的业务需求。
逻辑复用:
- 选项式 API 通过
mixin
来实现逻辑复用,mixin
是一种将多个对象的属性和方法合并到一个对象中的技术。但是,mixin
存在一些问题,比如命名冲突、数据来源不清晰等 - 组合式 API 通过函数来实现逻辑复用,开发者可以将相同的逻辑封装成一个函数,然后在不同的组件中复用这个函数。这种方式的优点是逻辑复用更加灵活和可控,能够避免
mixin
存在的问题
Vue3 里为什么要用 Proxy 替代 defineProperty?
在 Vue 3.0 中,使用 Proxy API 替代 defineProperty API 是为了改进响应式系统的性能和功能:
- 性能提升:Proxy API 比 defineProperty API 在许多情况下具有更好的性能。defineProperty 使用 Object.defineProperty 方法来拦截对象属性的访问和修改,但它需要遍历每个属性进行拦截。而 Proxy API 允许拦截整个对象,可以更高效地捕获对对象的访问和修改。
- 更全面的拦截能力:Proxy API 提供了更多的拦截方法,比 defineProperty API 更灵活、丰富。它支持拦截目标的各种操作,包括读取、设置、删除、枚举等,甚至还可以拦截函数调用和构造函数实例化。
- 更好的数组变化检测:Vue 3.0 使用 Proxy API 改善了数组的变化检测机制。Proxy 可以直接拦截数组的索引访问和修改,使得对数组的变化更容易被监听到,从而提供了更可靠的响应式行为。
- 更易于处理嵌套对象:Proxy API 能够递归地拦截对象的嵌套属性,而 defineProperty 无法自动递归处理嵌套对象。这使得在 Vue 3.0 中处理嵌套对象更加简单和方便。
- 更好的错误提示:相比于 defineProperty,Proxy API 提供了更好的错误追踪和调试信息。当使用 Proxy API 时,如果访问或修改了一个不存在的属性,会直接抛出错误,从而更容易发现和修复问题。
使用 Proxy API 取代 defineProperty API 是为了提升性能、增强功能,并提供更好的开发体验和错误提示。这些改进使得 Vue 3.0 的响应式系统更加高效、灵活和可靠。
mixins 混入的理解
Mixin 是一种在 JavaScript 中实现代码复用的方式,它允许你将多个对象的属性和方法合并到一个新的对象中。
Mixin 对象可以包含组件的 data、methods、computed、watch 等选项,以及生命周期钩子函数。
ue3 不主推这种方法 Vue3 主推自定义 hooks 替代 Mixins
缺点:
- 变量来源不明确
- 多 mixins 可能会造成命名冲突
- mixins 和组件出现多对多的关系,使项目复杂度变高
解决缺点:
- Vue3 的组合 API 解决了 mixins 引起的所有问题(不清晰的数据来源,命名冲突等),这也是 Vue3 中组合式 API 出现的原因之一
vue2 和 vue3 的区别?
Vue 3 带来了许多新特性和改进,下面是与 Vue 2 相比较著的几个区别:
ue2
使用的是选项式 APIoptionsAPI
,Vue3
使用组合式 APIcomposition API
,更好的组织代码,提高代码可维护性Vue3
使用Proxy
代理实现了新的响应式系统,比Vue2
使用Object.defineProperty
有着更好的性能和更准确的数据变化追踪能力。Vue3
引入了Teleprot
组件,可以将 DOM 元素渲染到 DOM 数的其他位置,用于创建模态框、弹出框等。Vue3
全局 API 名称发生了变化,同时新增了watchEffect
、Hooks
等功能Vue3
对TypeScript
的支持更加友好Vue3
核心库的依赖更少,减少打包体积vue3 支持更好的
Tree Shanking
,可以更加精确的按需要引入模块
vue3 的生命周期
- 创建阶段:在这个阶段,Vue 会创建一个空的实例,并初始化一些数据和方法。这个阶段的钩子函数有
beforeCreate
和created
。 - 挂载阶段:在这个阶段,Vue 会将实例挂载到 DOM 元素上,并渲染视图。这个阶段的钩子函数有
beforeMount
和mounted
。 - 更新阶段:在这个阶段,当数据发生变化时,Vue 会更新视图。这个阶段的钩子函数有
beforeUpdate
和updated
。 - 销毁阶段:在这个阶段,Vue 会销毁实例,并释放相关的资源。这个阶段的钩子函数有
beforeDestroy
和destroyed
。
Vue 还提供了一些其他的钩子函数,例如 activated
和 deactivated
,用于在组件被激活或停用的时候执行一些操作。
vue3 的模板编译优化了解吗?
Vue3 的模板编译优化主要包括以下几个方面:
静态提升:Vue3 会将模板中的静态节点提升到渲染函数的外部,只生成一份,而不是每次渲染都重新创建。这样可以减少内存占用和渲染时间。
事件监听缓存:Vue3 会缓存事件监听函数,避免重复创建。这样可以提高性能,特别是在频繁触发事件的情况下。
插槽编译优化:Vue3 对插槽的编译进行了优化,减少了不必要的渲染和更新。
模板预编译:Vue3 支持模板预编译,可以将模板编译成 JavaScript 函数,而不是在运行时解析模板。这样可以提高性能,特别是在大型应用中。
优化指令:Vue3 对一些指令进行了优化,例如
v-if
、v-for
等。这些指令的性能得到了显著提高。
vue3 的 setup 是怎么实现的?
setup()
钩子是在组件中使用组合式 API 的入口
起初 Vue3.0 暴露变量必须
return
出来,template
中才能使用;Vue3.2 后 只需要在
script
标签上加上setup
属性,组件在编译的过程中代码运行的上下文是在setup()
函数中,无需return
,template
可直接使用。在
setup()
函数中返回的对象会暴露给模板和组件实例。其他的选项也可以通过组件实例来获取setup()
暴露的属性setup
函数的第一个参数是组件的props
。和标准的组件一致,一个setup
函数的props
是响应式的,并且会在传入新的 props 时同步更新。如果你解构了props
对象,解构出的变量将会丢失响应性。因此我们推荐通过props.xxx
的形式来使用其中的 props。setup
函数的第二个参数是一个 Setup 上下文对象。上下文对象暴露了其他一些在setup
中可能会用到的值export default { setup(props, context) { // 透传 Attributes(非响应式的对象,等价于 $attrs) console.log(context.attrs) // 插槽(非响应式的对象,等价于 $slots) console.log(context.slots) // 触发事件(函数,等价于 $emit) console.log(context.emit) // 暴露公共属性(函数) console.log(context.expose) } }
对于结合单文件组件使用的组合式 API,推荐通过
<script setup>
以获得更加简洁及符合人体工程学的语法。
关于<script setup>
<script setup>
(SFC) 中使用组合式 API 的编译时语法糖。当同时使用单文件组件与组合式 API 时该语法是默认推荐。相比于普通的<script>
语法,它具有更多优势:
- 更少的样板内容,更简洁的代码。
- 能够使用纯 TypeScript 声明 props 和自定义事件。
- 更好的运行时性能 (其模板会被编译成同一作用域内的渲染函数,避免了渲染上下文代理对象)。
- 更好的 IDE 类型推导性能 (减少了语言服务器从代码中抽取类型的工作)。
setup 带来的改变:
- 属性和方法无需返回,可以直接使用
- 组件直接挂载,无需注册
- 自定义的指令也可以在模版中自动获得
- this 不再是这个活跃实例的引用
- 默认不会对外暴露任何属性,如果有需要可使用 defineExpose
- 带来的大量全新 api,比如 defineProps,defineEmits,withDefault,toRef,toRefs
computed 和 watch 有什么区别?
我先说下计算属性和 watch 的概念:
计算属性:
- 当一个属性的结果需要通过其它数据运算得来, 此时就可以把这个属性定义成计算属性
- 计算属性是有缓存的, 多处去使用计算属性也只会计算一次, 除非依赖的数据发生变化
- 计算属性有完整写法, 可以通过 get 和 set 方法实现
- 应用场景: 购物车总价, 全选
watch:
- watch 是一个侦听器, 如果某个属性的值发生变化, 我们想要去做一些业务操作, 我们就可以用 watch 去侦听该属性
- watch 可以通过 deep 属性去实现深度侦听
- 应用场景: 实时翻译
再说一下计算属性和 watch 的区别:
- 计算属性是属性, watch 则是对属性的侦听
- 计算属性内部不能有异步的操作, 但是 watch 是可以有异步操作的
vue3 怎么做性能优化?
v-if 和 v-for 不能连用:如果需要根据条件渲染列表,建议将
v-if
移动到v-for
的外层,或者使用计算属性来过滤列表。页面采用 keep-alive 缓存组件:这样可以避免组件的重复渲染,提高性能。
合理使用 v-if 和 v-show:
v-show
只是切换元素的显示状态,而v-if
会真正地创建或销毁元素。如果需要频繁切换元素的显示状态,建议使用v-show
。key 保证唯一:在使用
v-for
渲染列表时,一定要给每个元素设置唯一的key
。使用路由懒加载、异步组件、组件封装实现复用
防抖、节流
第三方模块按需导入
图片懒加载
代码压缩:在生产环境中,建议对代码进行压缩和优化,以减少文件的大小,提高加载速度。
CDN 外链:
把项目中的三方库在打包的时候先排出
使用 CDN 的外部链接引入, 这样就能减少包的体积, 提高首屏加载的速度
ES6 新增了什么?
- 块级作用域:使用
let
和const
关键字声明变量,具有块级作用域,避免了变量提升和全局污染的问题。 - 解构赋值:可以使用解构赋值语法从对象和数组中提取值,使代码更加简洁。
let { a, b } = { a: 1, b: 2 }
- 箭头函数:使用箭头
=>
定义函数,语法更加简洁,并且可以自动绑定this
上下文。 - 模板字符串:使用反引号(`)定义字符串,可以在字符串中插入变量和表达式,并且支持多行字符串。
- 剩余参数和扩展运算符:使用
...
语法表示剩余参数和扩展运算符,可以方便地处理不定数量的参数和数组。 - 数组方法:map、filter、every、reduce 等等
- 函数参数默认值:可以为函数参数设置默认值,使函数更加灵活。
fn(a = 1) {}
- Promise 异步编程解决方案:Promise 是一种处理异步操作的新方式,可以避免回调地狱,使代码更加清晰
- 模块化:import–引入、exprot default–导出
- Map 和 Set 数据结构:Map 和 Set 是两种新的数据结构,分别用于存储键值对和唯一值。
- async/await(es8)
TS 的特点是什么?
面向对象编程:TypeScript 支持面向对象编程,包括类、接口、继承、多态等特性。
ES6 + 语法:TypeScript 支持 ES6 + 的语法,包括箭头函数、模板字符串、解构赋值等。
模块系统:TypeScript 支持 ES6 的模块系统,可以将代码拆分成多个模块,提高代码的可维护性和可复用性。
工具支持:TypeScript 提供了丰富的工具支持,包括编译器、代码编辑器、调试器等,可以提高开发效率。
与 JavaScript 兼容:TypeScript 可以与 JavaScript 兼容,可以在现有的 JavaScript 项目中逐步引入 TypeScript。
Vuex 和 Pinia 的区别
是什么
Vuex 是 Vue2 的状态管理工具
Pinia 是 Vue3 的状态管理工具
区别
Pinia 对 Vue2/3 的兼容性更好,支持 TypeScript
Pnina 是 Vuex 的替代版,符合 Vue3 组合式 API,让代码扁平化
Pnina 抛弃传统的 mutation,只有 state,getter 和 action,简化状态管理