当面试官问:为什么 Vue3.0 要重写响应式系统?

勾勾的前端世界

共 4034字,需浏览 9分钟

 ·

2021-01-24 10:39

嗨,我是你稳定更新、精通面试的勾勾。



以前面试的时候经常被问到响应式相关的内容,而 Vue3.0 更新后,面试官又有了新的武器来考核面试者。


面试官:为什么 Vue3.0 要重写响应式系统?



对于面试者来说,懵逼树上懵逼果,懵逼树下你和我,面试官在问什么,我该怎么回答,完全不知道怎么回事。


有些经验的小伙伴可能会从解释 Proxy 的好处开始简单聊一下,比如,Proxy 是直接代理对象,而不是劫持对象的属性,更好的数组监控等。


这样的回答,勉强算是合格吧。


那到底应该怎么答呢,才能顺利通过面试,赢得 offer?


面试官背后的出题逻辑


别急,咱们先整理一下思路,孙子兵法有云:“知己知彼,百战不殆”


面试就像打仗,你来我往,所以我们需要换位思考,想一想。


为什么面试官会问这样一个问题?

面试官想从这个问题里得到什么回答?

这个问题可以考察那些技术点?


想清楚这些问题,再回到自己身上,去思考这些技术点自己是否都已经掌握。


说的直白一点,面试就像考试,你需要先读题审题才能答好这道题。


为什么很多人认为“面试造火箭,工作拧螺丝”?


因为没有换位思考,没有想清楚面试题背后的逻辑。


那我们想清楚这个逻辑之后,需要我们做的就是提取技术点——整理思路——做出对应解答。


当然,前提是你需要具备这些技术能力。


那么接下来,我就尝试拆解一下这个面试题了,提取其中的知识点。对于你来说,就是要看看这些知识点,你都掌握了多少?


为什么 Vue3.0 要重写响应式系统?


为什么要重写?


如果之前好好的,重写就没有意义。那之前存在什么问题,现在是怎么解决的,这就是关键点了。


不知道你对 Vue2.x 的响应式掌握多少,是不是欠下了技术的债呢?


没关系,我来帮你还债,先梳理 Vue2.x 的响应式


其实基于这个面试题,背后还有很多技术点。上面这些,是与当前题目有直接关系的。在实际面试中,很有可能基于这些技术点,再进行深入交流,这里就不扩展了,你能把现在这些问题理清楚,就算赚到了!



Vue2.x 响应式


关于这一点,在 Vue 的官方文档中,早已经有过说明了,而且说的非常详细。


官方文档:

https://cn.vuejs.org/v2/guide/reactivity.html



当你把一个普通的 JavaScript 对象传入 Vue 实例作为 data 选项,Vue 将遍历此对象所有的 property,并使用 Object.defineProperty 把这些 property 全部转为 getter/setter。


Object.defineProperty 是 ES5 中一个无法 shim 的特性,这也就是 Vue 不支持 IE8 以及更低版本浏览器的原因。


这些 getter/setter 对用户来说是不可见的,但是在内部它们让 Vue 能够追踪依赖,在 property 被访问和修改时通知变更。


这里需要注意的是,不同浏览器在控制台打印数据对象时对 getter/setter 的格式化并不同,所以建议安装 vue-devtools 来获取对检查数据更加友好的用户界面。


每个组件实例都对应一个 watcher 实例,它会在组件渲染的过程中把“接触”过的数据 property 记录为依赖。之后当依赖项的 setter 触发时,会通知 watcher,从而使它关联的组件重新渲染。


我们使用官方给的一张图示,来梳理整个流程。



先来看一段代码:



响应式原理


data 中的 obj 就是一个普通的 JavaScript 对象,通过点击 Click 按钮,将获取到的随机数赋值给 this.message ,而 this.message 指向的就是 data 中 obj 对象的 message 属性。


当 message 发生数据改变时,页面中 H1 标签的内容会随之改变,这个过程就是就是响应式的。


那么 Vue 是如何实现的呢?


首先,Vue 内部使用 Object.defineProperty() 将 Data 中的每一个成员都转换为 getter / setter 的形式。


getter 用来依赖收集,setter 用来派发更新。而模板内容,最终会被编译为 render 函数。


在 render 函数中,我们能发现 _v(_s(message)) message 被访问了,就会触发 getter 来进行依赖收集。


而在代码中的点击事件中,一旦事件处理程序被触发执行,那么 message 则会被修改,就会触发 setter 来进行派发更新。


虽然流程理清楚了,但是总感觉少点什么,怎么才能更通透呢?


我们用代码来模拟整个的实现过程。


defineProperty 模拟代码


defineProperty 的基本用法,直接看手册就行了:


https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty


我们来看看代码:

<div id="app">     hello div> <script>     // 模拟 Vue 中的 data 选项     let data = {       msg: 'hello'     }     // 模拟 Vue 的实例     let vm = {}     // 数据劫持:当访问或者设置 vm 中的成员的时候,做一些干预操作     Object.defineProperty(vm, 'msg', {       // 可枚举(可遍历)       enumerable: true,       // 可配置(可以使用 delete 删除,可以通过 defineProperty 重新定义)       configurable: true,       // 当获取值的时候执行       get () {         console.log('get: ', data.msg)         return data.msg       },       // 当设置值的时候执行       set (newValue) {         console.log('set: ', newValue)         if (newValue === data.msg) {           return         }         data.msg = newValue         // 数据更改,更新 DOM 的值         document.querySelector('#app').textContent = data.msg       }     })     // 测试     vm.msg = 'Hello World'     console.log(vm.msg) script>


你没有看错,加上注释,一共 36行代码,这就是 Vue2.x 对响应式实现的整个流程。


 继续实现多个数据的响应。

<body>  <div id="app">    hello  div>  <script>    // 模拟 Vue 中的 data 选项    let data = {      msg: 'hello',      count: 10    }    // 模拟 Vue 的实例    let vm = {}    proxyData(data)    function proxyData(data) {      // 遍历 data 对象的所有属性      Object.keys(data).forEach(key => {        // 把 data 中的属性,转换成 vm 的 setter/setter        Object.defineProperty(vm, key, {          enumerable: true,          configurable: true,          get () {            console.log('get: ', key, data[key])            return data[key]          },          set (newValue) {            console.log('set: ', key, newValue)            if (newValue === data[key]) {              return            }            data[key] = newValue            // 数据更改,更新 DOM 的值            document.querySelector('#app').textContent = data[key]          }        })      })    }    // 测试    vm.msg = 'Hello World'    console.log(vm.msg)script>body>


上面的代码只是模拟了响应式的原理,但 Vue 在实现中,肯定不会那么简单。


下周一,我们来康康源码(●'◡'●)。


推荐阅读:

喜大普奔!Element UI for Vue 3.0 来了!

Proxy 代理对象

不小心将 Webpack 升级后我搞定了微前端。

别觉得搞前端就不需要懂后台知识。

腾讯QQ偷我浏览记录到底想干嘛。

是我 Web 端配不上阿里了。


点点“”和“在看”,保护头发,减少bug。

浏览 42
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报