Vue.js - 响应式、Diff算法

294 阅读3分钟

「这是我参与2022首次更文挑战的第11天,活动详情查看:2022首次更文挑战

Vue.js - 响应式 题解

前言

只要功夫深,铁杵磨成针

理论功夫再多也需要实践出真章,接下来,让我们进入实践环节吧!

题目1

当我们点击按钮的时候动态data增加的成员是否响应式数据,如果不是的话,如何把新增成员设置成响应式数据,他的内部原理是什么?

示例代码:

let vm = new Vue({
    el: '#el'
    data: {
        o: 'object',
        dog: {}
    },
    method: {
        clickHandler () {
            // 该 name 属性是否是响应式的
            this.dog.name = 'Trump'
        }
    }
})
  1. this.dog.name 并不是响应式数据
  2. this.$set( this.dog, 'name', 'Trump' )
  3. 利用 Object.defineProperty 的 getter 和 setter 实现响应式数据,这也有了很多的不足之处

不足之处:

虽然通过Object.defineProperty方法实现了对object数据的可观测,但是这个方法仅仅只能观测到object数据的取值及设置值,当我们向object数据里添加一对新的key/value或删除一对已有的key/value时,它是无法观测到的,导致当我们对object数据添加或删除值时,无法通知依赖,无法驱动视图进行响应式更新。

不仅如此,对数组的监测也很弱,vue中对于数组变化侦测是通过拦截器实现的,也就是说只要是通过数组原型上的方法对数组进行操作就都可以侦测到,但是别忘了,我们在日常开发中,还可以通过数组的下标来操作数据,这样也会导致视图无法进行更新。。。

Vue也注意到了这个问题, 为了解决这一问题,Vue增加了两个全局API:Vue.set和Vue.delete

题目2

请简述 Diff 算法的执行过程

  • 查找两棵树每一个节点的差异
  • 当数据变化之后不直接操作DOM,而是用js对象进行描述DOM,当数据发生变化后,先比较JS对象是否发生变换找到树变化的位置,找到最小化变化的位置更新,从而提高性能

这里就引发了一个问题思考:

直接操作 DOM 的性能真的会低于虚拟 DOM 和 Diff 算法吗?

其实不,Diff 算法有比较过程,比较是为了找出不同从而有的放矢的更新页面。但是比较也是要消耗性能的。而直接操作 DOM 就是有的放矢,我们知道该更新什么不该更新什么,所以不需要有比较的过程。所以直接操作 DOM 效率可能更高。

React 厉害的地方并不是说它比 DOM 快,而是说不管你数据怎么变化,我都可以以最小的代价来进行更新 DOM。方法就是我在内存里面用新的数据刷新一个虚拟 DOM 树,然后新旧 DOM 进行比较,找出差异,再更新到 DOM 树上。

框架的意义在于为你掩盖底层的 DOM 操作,让你用更声明式的方式来描述你的目的,从而让你的代码更容易维护。没有任何框架可以比纯手动的优化 DOM 操作更快,因为框架的 DOM 操作层需要应对任何上层 API 可能产生的操作,它的实现必须是普适的。 # virtual DOM和真实DOM的区别_聊聊虚拟DOM的真正价值