Vue(4),三面美团、四面阿里成功斩下offer

return newVal;

},

},

},

mounted() {

setTimeout(() => {

this.getC = 8;

}, 800);

},

watch: {

getC: {

handler: function () {

console.log(this.getC, “c无法被监听”);//无法打印

},

},

},

computed内部Object.defineProperty中的set没有做任何通知依赖变化的操作。initComputed最终获取的是一个值,它可以依赖某个响应式数据,也可以不依赖。如果依赖于一个响应式数据或者多个响应式数据,那么当响应式数据发生变化了,它也跟着变化这是因为响应式数据中使用了new Dep创建了dep实例,并且在set函数通知了那些依赖它的watcher。

那为什么不被watch选项监听呢?

watch选项监听的是响应式数据,执行watch选项的回调函数是在dep通知更新变化的时候去执行的,那不依赖于响应式数据的computed对象怎能做到被通知变化了呢!这样子说watch是用来监听一个值的变化,接收的值是一个新变化的值合情合理了。

回到最初的疑问,immediate:true的实现原理什么?

在开启immediate:true时,会先执行watch的回调函数,这是因为js是单线程的,在_init初始化时initWatchmounted早。initWatch的关键是vm.$watch,在实现这个函数的时候,判断了immediate是否为true,如果是true就立即执行了callback函数。

通过这些内容,实现缓存机制的一种想法已经浮现在我的脑袋中了,合理利用好Object.defineProperty可以实现一些数据的拦截,也是相当ok的!

初始响应式数据

props和data选项都是响应式数据,Vue是如何将propsdata的数据变成可观察的?

对象是通过使用Object.defineProperty进行包装整合,数组是通过将数组的方法进行重写。

在Vue源码中,通过一个Observer类实现数据的劫持,也就是说当初始化data和props时,调用observer方法。该方法进行了数据类型的判断,决定是重新包装对象,还是重写方法。那这和响应式有什么关系?

疑惑

当我在data选项里定义了一个变量a之后,改变了变量a的值,为何所有用到它的地方都会自动更新值呢?

思考

响应式数据其关键的还是Watcher类和Dep类在中间起了关键的角色。那这两个类具体做了什么事情?

  • Watcher(被观察者)作用

1、在自身实例化时往属性订阅器(dep)里面添加自己。

2、自身必须有一个update()方法。

3、待属性变动dep.notice()通知时,能调用自身的update()方法,

  • Dep(观察者)作用

1、有个框子来收集着每一个watcher。

2、有个收集watcher的addSub()方法。

3、有个通知的方法,通知watcher进行更新。

  • 提炼了两者的作用之后,那它们又是如何工作的?

Wtacher类在实例化时,通过定义Dep类身上的target属性将该watcher实例关联起来了。那么对于变量a,在data初始化使用Object.defineProperty进行包装时,通过new Dep类(ps:这个dep实例可以看出一个框子,通过框子去收集这些依赖变量a的watcher实例)实现依赖变量a的watcher实例被收集了。

这个dep实例实际上是属于变量a的小框子,它将依赖它的watcher放进了dep定义的小框子里。等待变量a发生改变时,在set函数里触发dep的notify函数通知所有watcher调用update函数更新值。

再比如我在computed选择定义了一个getA的属性,在初始化computed时new Watcher会把自身getA设置为Dep.target。如果getA属性有依赖于data选项定义的变量a值,在获取变量a的值时会触发Object.defineProperty的get方法,在该方法里收集getA的watcher依赖,也就是会将getA丢到了变量a的dep框里。

所以Observer类的实现并不难,关键是Watcher类和Dep类。

  • 如何实现Watcher类和Dep类

我通过模拟Vue源码写了一份伪代码,可供参考:

Watcher类和工具函数: image

Dep类:

到这里,你应该清晰的了解到响应式数据是如何实现了吧,而不是仅仅因为Object.defineProperty~

回归到Vue的响应式数据data/props,在源码中还做了一层代理,因此我们写代码的时候就可以直接通过this.xxx来访问变量了。

写这段伪代码的时候,让我想起了es6的Proxy类。

初始nextTick

在了解nextTick之前,我们先来看一个案例吧。

案例

有一种情况:在mounted时,test的值会被++循环执行1000次。 每次++时,都会根据响应式触发setter->Dep->Watcher->update->patch。

思考:Vue如何是如何更新视图的以及和nextTick有什么关系?

Vue是异步更新视图的,Vue实现了一个queue队列。先执行主线程的代码,等下一个tick的时候会统一执行queue中Watcher的run。这里在说下一个tick那得先理解一下事件循环。可参考学习大佬写的:事件循环

同时,拥有相同id的Watcher不会被重复加入到该queue中去,所以不会执行1000次Watcher的run。最终更新视图只会直接将test对应的DOM的0变成1000。

而之所以会在nextTick回调函数中能获取到数据修改后的DOM变化,是因为nextTick函数中定义了timerFunc函数,这个函数使用PromiseMutationObserversetImmediatesetTimeout进行包装,开启了另外的一个宏任务,当前的宏任务执行完毕,都会清空当前宏任务所产生的微任务(ps:Watcher的run被执行了)。

那我们在异步更新视图之后(ps:数据早更新了),想要获取到数据修改后的DOM变化,要再开启一个tick,所以使用nextTick传入的回调函数,在回调函数就可操作修改后的DOM变化,可以在这里写你的代码逻辑了。这就是为什么操作更新完毕的数据的dom元素要在nextTick的原因。

在nextTick函数中使用 callbacks 而不是直接在 nextTick 中执行回调函数的原因是保证在同一个 tick 内多次执行 nextTick,不会开启多个异步任务,而把这些异步任务都压成一个同步任务,在下一个 tick 执行完毕。

似想如果这时候没有异步更新视图,那么每次++都会直接操作DOM更新视图,这是非常消耗性能的。

初始事件机制

Vue.js提供了四个事件API,分别是$on$once$off$emit

分析
  • $on订阅函数,传入事件名称,以及cb。一个事件可被订阅多次,所以一个事件通过队列的形式进行cb的收集。

  • $emit发布函数,通过对应的事件名称去执行刚刚收集的cb函数。

  • $once只订阅一次,这里的思想是使用函数包装:将传入的cb进行包装,然后订阅包装函数,包装函数逻辑是先调用cb再取消订阅。那什么时候会触发包装函数?就是当$emit时候。

还有一个小细节:利用函数的特性给包装函数绑定属性,将传入的cb绑定到包装函数的某个属性上。这个作用是什么?(ps:留个疑问,后续讲述)

  • $off是移除事件监听,源码中分了几种情况:

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

深知大多数前端工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

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

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上前端开发知识点,真正体系化!

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

如果你觉得这些内容对你有帮助,可以添加V获取:vip1024c (备注前端)
img

最后更多分享:前端字节跳动真题解析

深入学习提升的进阶课程,基本涵盖了95%以上前端开发知识点,真正体系化!**

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

如果你觉得这些内容对你有帮助,可以添加V获取:vip1024c (备注前端)
[外链图片转存中…(img-bldIBkXT-1712002925852)]

最后更多分享:前端字节跳动真题解析
  • [外链图片转存中…(img-QrA34f6k-1712002925852)]
  • 27
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值