当面试官问:为什么 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。

浏览 48
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报
评论
图片
表情
推荐