面试前端八股文十问十答第五期
相信看了本文后,对你的面试是有一定帮助的!关注专栏后就能收到持续更新!
⭐点赞⭐收藏⭐不迷路!⭐
1)介绍节流防抖原理、区别以及应用
**节流(Throttling)**是一种限制事件处理频率的技术。它确保在一定时间间隔内,事件处理函数只会被执行一次。如果在指定的时间间隔内多次触发事件,只有第一次触发会立即执行处理函数,随后的触发会被忽略,直到过了指定的时间间隔,才会再次执行处理函数。
**防抖(Debouncing)**是一种延迟执行的技术。它确保在事件触发后,只有在指定的时间间隔内没有再次触发时才会执行事件处理函数。如果在指定的时间间隔内又触发了相同的事件,则重新开始计时,等待下一次事件触发。
区别:
- 时间点: 节流在一段时间内只执行一次,而防抖则在事件停止触发一段时间后执行。
- 执行时机: 节流在一定时间内的连续触发事件中只执行第一次,而防抖在最后一次事件触发后的指定时间间隔内执行。
- 适用场景: 节流适用于需要限制处理频率的场景,例如滚动事件、resize 事件等;防抖适用于需要等待一段时间后再执行处理函数的场景,例如输入框输入、按钮点击等。
应用:
- 节流: 滚动加载、窗口 resize 事件、输入框输入事件等。
- 防抖: 搜索框输入建议、按钮点击提交、窗口 resize 事件等。
2)简述MVVM
MVVM 是一种软件架构模式,用于构建用户界面。它将应用程序分为三个部分:模型(Model)、视图(View)和视图模型(ViewModel)。
- 模型(Model):负责管理应用程序的数据和业务逻辑,提供数据接口供视图模型访问。
- 视图(View):用户界面的呈现层,负责展示数据、接收用户输入,并将用户操作传递给视图模型。
- 视图模型(ViewModel):连接视图和模型的中间层,负责处理视图的展示逻辑、响应用户输入,并调用模型层获取数据。它将模型数据转换为视图所需的数据格式,并通过数据绑定技术将视图和模型解耦。
MVVM 的优点:
- 分离关注点(Separation of Concerns): MVVM 将应用程序分为模型、视图和视图模型三个部分,各自负责不同的职责,使得代码结构更加清晰,易于维护和扩展。
- 可测试性(Testability): 由于视图模型将视图逻辑与界面分离,使得可以更方便地对视图模型进行单元测试,提高代码的可测试性。
- 数据驱动(Data-Driven): MVVM 使用数据绑定技术实现视图和视图模型之间的数据同步,使得视图可以自动更新以反映模型数据的变化,提高了开发效率。
3)Vue底层实现原理
Vue.js 是一款流行的前端 JavaScript 框架,它的底层实现原理主要包括以下几个方面:
- 响应式数据(Reactivity): Vue 使用响应式数据系统实现数据的双向绑定。它通过 Object.defineProperty() 方法对数据对象的属性进行劫持,当属性发生变化时,自动通知所有相关联的视图进行更新。
- 虚拟 DOM(Virtual DOM): Vue 使用虚拟 DOM 技术实现高效的 DOM 更新。它通过在内存中维护一个虚拟 DOM 树,将视图的状态与真实 DOM 进行比较,找出差异,并仅更新需要更新的部分,以减少 DOM 操作次数,提高性能。
- 模板编译(Template Compilation): Vue 将模板编译成渲染函数,以提高渲染性能。在编译阶段,Vue 将模板解析成抽象语法树(AST),然后将 AST 转换为渲染函数,最终生成可执行的 JavaScript 代码。
- 组件化(Component-Based Architecture): Vue 提供了组件化的开发方式,允许将页面拆分成独立的组件,每个组件都有自己的状态和视图。Vue 使用虚拟 DOM 和响应式数据系统实现了组件的高效更新和通信。
- 生命周期钩子(Lifecycle Hooks): Vue 提供了一系列的生命周期钩子函数,允许开发者在组件的不同阶段执行自定义逻辑。这些钩子函数包括 beforeCreate、created、beforeMount、mounted、beforeUpdate、updated、beforeDestroy 和 destroyed 等。
4)谈谈对vue生命周期的理解?
Vue 组件的生命周期包括创建、挂载、更新和销毁等阶段,每个阶段都有对应的生命周期钩子函数,可以在特定阶段执行相应的逻辑。
- 创建阶段(Creation):
- beforeCreate: 在实例初始化之后、数据观测 (data observer) 和 event/watcher 事件配置之前被调用。此时组件的实例还未初始化,无法访问数据和方法。
- created: 在实例创建完成后被立即调用。此时实例已经完成了数据观测,但是尚未挂载到 DOM 上。可以在这个钩子函数中执行异步操作或初始化数据。
- 挂载阶段(Mounting):
- beforeMount: 在挂载开始之前被调用,相关的
render
函数首次被调用。在这之后,Vue 实例的$el
和el
被关联,但尚未挂载到 DOM 上。 - mounted: 在实例挂载到 DOM 后被调用。此时,Vue 实例已经挂载到 DOM 上,可以进行 DOM 操作或访问 DOM 元素。
- beforeMount: 在挂载开始之前被调用,相关的
- 更新阶段(Updating):
- beforeUpdate: 在数据更新之前被调用,发生在虚拟 DOM 重新渲染和打补丁之前。可以在这个钩子函数中进行状态更新之前的准备工作。
- updated: 在数据更新完成后被调用。该钩子函数被调用时,DOM 已经更新,可以执行 DOM 相关的操作。但是,注意避免在这个钩子函数中触发无限循环的更新。
- 销毁阶段(Destroying):
- beforeDestroy: 在实例销毁之前被调用。此时,实例仍然完全可用,可以执行清理工作,如清除定时器、解绑事件等。
- destroyed: 在实例销毁之后被调用。此时,实例的所有指令已经解绑,所有子实例也被销毁,可以执行一些最终的清理工作。
5)computed与watch
- computed:
- 特点: 计算属性是基于它们的依赖进行缓存的,只有在相关依赖发生改变时才会重新求值。计算属性的值会被缓存,只有当依赖发生改变时才会重新计算。
- 适用场景: 当需要根据已有数据计算出新数据时,可以使用计算属性。例如,对数据进行过滤、排序、格式化等操作。
- watch:
- 特点: Watch 用于观察数据的变化并执行异步或开销较大的操作。可以监听数据的变化,并在数据变化时执行自定义的操作。
- 适用场景: 当需要在数据变化时执行异步操作、操作 DOM、或执行其他非纯粹数据操作时,可以使用 Watch。例如,监听输入框内容的变化并发送网络请求。
6)组件中的data为什么是一个函数?
在 Vue 组件中,data
选项需要是一个函数,而不是一个对象。这是因为 Vue 组件是可复用的,当一个组件被多次使用时,如果 data
是一个对象,那么所有的组件实例都会共享同一个 data
对象,导致数据互相影响,从而产生意料之外的结果。
通过将 data
定义为一个函数,每次创建一个新的组件实例时,Vue 会调用该函数返回一个新的数据对象,从而保证每个组件实例都有独立的数据对象,互相之间不会产生影响。这样做可以确保组件之间的数据隔离,提高了组件的可复用性和可维护性。
因此,为了避免数据共享和互相影响的问题,Vue 要求将 data
定义为一个返回数据对象的函数,而不是直接定义为一个对象。
7)为什么v-for和v-if不建议用在一起
在 Vue 中同时使用 v-for
和 v-if
可能会导致一些意料之外的结果,因为它们的优先级不同,可能会影响到渲染结果和性能。
- 优先级不同:
v-for
的优先级高于v-if
,意味着v-for
在每次渲染时都会运行,而v-if
的条件会在每次循环中重新评估。 - 性能影响: 当数据量较大时,在每次循环中重新评估
v-if
条件可能会导致性能问题,因为即使在某些情况下不需要渲染某些项,循环也会执行,这可能会导致不必要的渲染和性能损耗。 - 维护性差: 同时使用
v-for
和v-if
可能会导致模板变得难以理解和维护,因为在每次渲染时需要考虑循环和条件之间的交互关系。
虽然在某些情况下可能需要同时使用 v-for
和 v-if
,但通常建议尽量避免这种情况,可以通过重新组织数据、使用计算属性或在父组件中处理数据来减少 v-if
的使用,以提高代码的可读性和性能。
8)React/Vue 项目中 key 的作用
- React 中的 key: 在 React 中,
key
是用来标识列表中的每个元素的唯一性,帮助 React 识别哪些元素发生了变化、添加或删除。当列表中的元素发生变化时,React 会根据key
来判断是更新现有元素还是创建新元素,从而提高列表渲染的效率。通常,key
应该是列表中每个元素的唯一标识符,可以是元素的id
或其他唯一属性。 - Vue 中的 key: 在 Vue 中,
key
同样用于识别列表中的每个元素的唯一性,但其作用略有不同。key
主要用于 Vue 的虚拟 DOM 算法,在进行列表渲染时,Vue 会根据key
来判断哪些元素是新创建的、被删除的或是已经存在的,从而尽可能地复用已存在的 DOM 元素,减少不必要的 DOM 操作,提高渲染性能。
9)vue组件的通信方式
Vue 组件之间的通信可以通过以下几种方式实现:
- Props / Emit: 父子组件之间通过 Props(属性)传递数据,子组件通过 Emit(事件)向父组件发送消息。这是最基本的一种通信方式,适用于父子组件之间的简单通信。
- 事件总线: 使用 Vue 的实例作为事件总线,通过
$emit
和$on
来进行组件间的通信。可以用于兄弟组件之间的通信或跨级组件之间的通信。 - Vuex: Vuex 是 Vue 的状态管理库,用于集中式管理应用的所有组件的状态。通过在组件中派发 mutations 或 actions 来改变状态,从而实现组件间的通信和状态共享。
- Provide / Inject: 父组件通过
provide
提供数据,子组件通过inject
注入数据。适用于跨级组件之间的通信,但不推荐用于跨多层级的通信,以避免组件之间的耦合。 - 事件总线: 使用第三方的事件总线库(如 EventBus)来实现组件间的通信。通过订阅和发布事件来实现组件之间的解耦。
10)nextTick的实现
nextTick
是 Vue 提供的一个异步方法,用于在 DOM 更新之后执行回调函数。它的实现原理是利用了浏览器的 microtask 和 macrotask 机制,确保回调函数在 DOM 更新之后执行。
具体来说,当调用 nextTick
方法时,Vue 会将传入的回调函数放入一个队列中,然后通过 microtask 或 macrotask 来执行这个队列中的回调函数。
- 在现代浏览器中,Vue 使用 microtask(如 Promise)来异步执行回调函数,确保回调函数在 DOM 更新之后执行,但在当前 JavaScript 执行栈之后、下一个 UI 更新之前执行。
- 在较老的浏览器中,如果不支持 microtask,则 Vue 会使用 macrotask(如 setTimeout)来异步执行回调函数,但会在下一个 UI 更新之后执行。
无论使用 microtask 还是 macrotask,nextTick
都能确保回调函数在 DOM 更新之后执行,从而避免了一些可能导致的 UI 更新问题。
开源项目地址:https://gitee.com/falle22222n-leaves/vue_-book-manage-system
前后端总计已经 900+ Star,1.5W+ 访问!
⭐点赞⭐收藏⭐不迷路!⭐