前端面试Vue 高频原理篇+详细解答,还有105道vue面试题集合

本文详细解释了Vue中的Dep和Watcher类在数据绑定中的作用,模板编译过程,生命周期钩子的工作原理,以及data函数作为函数的原因,还讨论了watch和computed的区别,以及$nextTick的使用场景。
摘要由CSDN通过智能技术生成

tip:Dep 是一个用来负责收集 Watcher 的类,Watcher 是一个封装了渲染视图逻辑的类,用于派发更新的。需要注意的是 Watcher 是不能直接更新视图的还需要结合Vnode经过patch()中的diff算法才可以生成真正的DOM

  • 每一个属性都有自己的 dep 属性,来存放依赖的 Watcher,属性发生变化后会通知 Watcher 去更新。

  • 在用户获取(getter) 数据时 Vue 给每一个属性都添加了 dep 属性来(collect as Dependency)收集 Watcher。在用户 setting 设置属性值时 dep.notify() 通知 收集的Watcher 重新渲染。详情见上面的 defineReactive()

  • Dep依赖收集类 其和 Watcher类 是多对多双向存储的关系

  • 每一个属性都可以有多个 Watcher 类,因为属性可能在不同的组件中被使用。

  • 同时一个 Watcher 类 也可以对应多个属性。

6. Vue 中的模板编译


Vue中模板编译:其实就是将 template 转化成 render 函数。说白了就是将真实的 DOM(模板) 编译成虚拟 dom(Vnode)

  • 第一步是将 template 模板字符串转换成 ast 语法树 (parser 解析器),这里使用了大量的正则来匹配标签的名称,属性,文本等。

  • 第二步是对 AST 进行静态节点 static 标记,主要用来做虚拟 DOM 的渲染优化(optimize优化器),这里会遍历出所有的子节点也做静态标记

  • 第三步是 使用 ast语法树 重新生成 render 函数 代码字符串 code。(codeGen 代码生成器)

为什么要静态标记节点,如果是静态节点(没有绑定数据,前后不需要发生变化的节点)那么后续就不需要 diff 算法来作比较。

7. 生命周期钩子实现原理


  • vue 中的生命周期钩子只是一个回调函数,在创建组件实例化的过程中会调用对应的钩子执行。

  • 使用Vue.mixin({})混入的钩子或生命周期中定义了多个函数,vue 内部会调用mergeHook() 对钩子进行合并放入到队列中依次执行

  • 扩展

// src\core\util\options.js

function mergeHook (

parentVal: ?Array,

childVal: ?Function | ?Array

): ?Array {

const res = childVal

? parentVal

? parentVal.concat(childVal) // 合并

Array.isArray(childVal)

? childVal

[childVal]

parentVal

return res

? dedupeHooks(res)
res

}

复制代码

8.老生常谈之 vue 生命周期有哪些,一般在哪里发送请求?


  • beforeCreate: 刚开始初始化 vue 实例,在数据观测observer之前调用,还没有创建 data/methods 等属性

  • created: vue 实例初始化结束,所有的属性已经创建。

  • beforeMount: 在 vue 挂载数据到页面上之前,触发这个钩子,render 函数此时被触发。

  • mounted: el 被 创建的vm.$el替换,vue 初始化的数据已经挂载到页面之上,这里可以访问到真实的 DOM。一般会在这里请求数据。

  • beforeUpdate: 数据更新时调用,也就是在虚拟 dom 重新渲染之前。

  • updated: 数据变化导致虚拟 dom 发生重新渲染之后发生。

  • beforeDestroy: 实例销毁之前调用该钩子,此时实例还在。vm.$destroy 触发两个方法。

  • destroyed: Vue 实例销毁之后调用。所有的事件监听都会被接触。

请求数据要看具体的业务需求决定在哪里发送 ajax

9.Vue.mixin({})的使用场景和原理


  • 使用场景:用于抽离一个公共的业务逻辑实现复用。

  • 实现原理:调用 mergeOptions() 方法采用策略模式针对不同的属性合并。混入的数据和组件的数据有冲突就采用组件本身的。

  • Vue.mixin({}) 缺陷,1.可能会导致混入的属性名和组件属性名发生命名冲突;2. 数据依赖的来源问题

  • 扩展

export function mergeOptions (

parent: Object,

child: Object,

vm?: Component

): Object {

// some code

if (!child._base) {

if (child.extends) {

parent = mergeOptions(parent, child.extends, vm)

}

if (child.mixins) {

for (let i = 0, l = child.mixins.length; i < l; i++) {

parent = mergeOptions(parent, child.mixins[i], vm)

}

}

}

// 递归遍历合并组件和混入的属性

const options = {}

let key

for (key in parent) {

mergeField(key)

}

for (key in child) {

if (!hasOwn(parent, key)) {

mergeField(key)

}

}

function mergeField (key) {

const strat = strats[key] || defaultStrat

options[key] = strat(parent[key], child[key], vm, key)

}

return options

}

复制代码

10.老生常谈之 vue 组件中的data 为什么必须是一个函数?


  • 这和 js 本身机制相关,data 函数中返回的对象引用地址不同,就能保证不同组件之间的数据不相互污染。

  • Vue.mixin() 中如果混入data属性,那么 data 也必须是一个函数。因为Vue.mixin()也可以多处使用。

  • 实例中data可以是一个对象也可以是一个函数,因为我们一个页面一般只初始化一个Vue实例(单例)

11. 老生常谈之 vue 中 vm.$nextTick(cb)实现原理和场景


  • 场景:在 dom 更新循环结束后调用,用于获取更新后的 dom 数据

  • 实现原理:vm.$nextTick(cb) 是一个异步的方法为了兼容性做了很多降级处理依次有 promise.then,MutationObserver,setImmediate,setTimeout。在数据修改后不会马上更新视图,而是经过 set 方法 notify 通知 Watcher 更新,将需要更新的 Watcher 放入到一个异步队列中,nexTick 的回调函数就放在 Watcher 的后面,等待主线程中同步代码执行借宿然后依次清空队列中,所以 vm.nextTick(callback) 是在 dom 更新结束后执行的。

上面将对列中Watcher 依次清空就是 vue 异步批量更新的原理。提一个小思考:为什么不直接使用setTimeout代替?因为setTimeout是一个宏任务,宏任务多性能也会差。

12.老生常谈之 watch 和 computed 区别


  • computed 内部就是根据 Object.definedProperty() 实现的

  • computed 具备缓存功能,依赖的值不发生变化,就不会重新计算。

  • watch 是监控值的变化,值发生变化时会执行对应的回调函数。

  • computedwatch 都是基于 Watcher类 来执行的。

computed 缓存功能依靠一个变量 dirty,表示值是不是脏的默认是 true,取值后是 false,再次取值时 dirty 还是 false 直接将还是上一次的取值返回。

// src\core\instance\state.js computed 取值函数

function createComputedGetter (key) {

return function computedGetter () {

const watcher = this._computedWatchers && this._computedWatchers[key]

if (watcher) {

if (watcher.dirty) { // 判断值是不是脏 dirty

watcher.evaluate()

}

if (Dep.target) {

watcher.depend()

}

return watcher.value

}

}

}

// src\core\instance\state.js watch 实现

Vue.prototype.$watch = function (

expOrFn: string | Function,

cb: any,

options?: Object

): Function {

const vm: Component = this

if (isPlainObject(cb)) {

return createWatcher(vm, expOrFn, cb, options)

}

options = options || {}

options.user = true

// 实例化 watcher

const watcher = new Watcher(vm, expOrFn, cb, options)

if (options.immediate) {

const info = callback for immediate watcher "${watcher.expression}"

pushTarget()

invokeWithErrorHandling(cb, vm, [watcher.value], vm, info)

popTarget()

}

return function unwatchFn () {

watcher.teardown()

}

}

Vue面试题集合

===========================================================================

面试光看这12道题怎么够呢?小编把vue面试题整理成了一个集合共有105道题目,不多但经典哦。

  • vue.js的两个核心是什么?

  • vue 的双向绑定的原理是什么?

  • vue生命周期钩子函数有哪些?

  • 请问 v-if 和 v-show 有什么区别?

  • vue常用的修饰符

  • nextTick

  • 什么是vue生命周期

  • 数据响应(数据劫持)

  • virtual dom 原理实现

  • Proxy 相比于 defineProperty 的优势

  • vuex

  • vue中 key 值的作用

  • Vue 组件中 data 为什么必须是函数?

  • v-for 与 v-if 的优先级

  • 说出至少 4 种 vue 当中的指令和它的用法

小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数初中级前端工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年Web前端开发全套学习资料》送给大家,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

img
img
img
img

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频

如果你觉得这些内容对你有帮助,可以添加下面V无偿领取!(备注:前端)
img

滞不前!**
因此收集整理了一份《2024年Web前端开发全套学习资料》送给大家,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

[外链图片转存中…(img-Sxe2KTR2-1710919552234)]
[外链图片转存中…(img-8ddyMpJO-1710919552234)]
[外链图片转存中…(img-fBqK3qWA-1710919552235)]
[外链图片转存中…(img-VBxYyxbc-1710919552236)]

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频

如果你觉得这些内容对你有帮助,可以添加下面V无偿领取!(备注:前端)
[外链图片转存中…(img-avQOQAUm-1710919552236)]

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值