Vue.js 响应式原理

本贴最后更新于 2680 天前,其中的信息可能已经时异事殊

写在前面

因为对 Vue.js 很感兴趣,而且平时工作的技术栈也是 Vue.js,这几个月花了些时间研究学习了一下 Vue.js 源码,并做了总结与输出。

文章的原地址:answershuto/learnVue

在学习过程中,为 Vue 加上了中文的注释 answershuto/learnVue,希望可以对其他想学习 Vue 源码的小伙伴有所帮助。

可能会有理解存在偏差的地方,欢迎提 issue 指出,共同学习,共同进步。

关于 Vue.js

Vue.js 是一款 MVVM 框架,上手快速简单易用,通过响应式在修改数据的时候更新视图。Vue.js 的响应式原理依赖于 Object.defineProperty,尤大大在 Vue.js 文档中就已经提到过,这也是 Vue.js 不支持 E8 以及更低版本浏览器的原因。Vue 通过设定对象属性的 setter/getter 方法来监听数据的变化,通过 getter 进行依赖收集,而每个 setter 方法就是一个观察者,在数据变更的时候通知订阅者更新视图。

将数据 data 变成可观察(observable)的

那么 Vue 是如何将所有 data 下面的所有属性变成可观察的(observable)呢?

function observer(value) {
    Object.keys(value).forEach((key) => defineReactive(value, key, value[key] , cb))
}

function defineReactive (obj, key, val, cb) {
    Object.defineProperty(obj, key, {
        enumerable: true,
        configurable: true,
        get: ()=>{
            /*....依赖收集等....*/
        },
        set:newVal=> {
            cb();/*订阅者收到消息的回调*/
        }
    })
}

class Vue {
    constructor(options) {
        this._data = options.data;
        observer(this._data, options.render)
    }
}

let app = new Vue({
    el: '#app',
    data: {
        text: 'text',
        text2: 'text2'
    },
    render(){
        console.log("render");
    }
})

为了便于理解,首先考虑一种最简单的情况,不考虑数组等情况,代码如上所示。在 initData 中会调用 observe 这个函数将 Vue 的数据设置成 observable 的。当_data 数据发生改变的时候就会触发 set,对订阅者进行回调(在这里是 render)。

那么问题来了,需要对 app._date.text 操作才会触发 set。为了偷懒,我们需要一种方便的方法通过 app.text 直接设置就能触发 set 对视图进行重绘。那么就需要用到代理。

代理

我们可以在 Vue 的构造函数 constructor 中为 data 执行一个代理 proxy。这样我们就把 data 上面的属性代理到了 vm 实例上。

_proxy(options.data);/*构造函数中*/

/*代理*/
function _proxy (data) {
    const that = this;
    Object.keys(data).forEach(key => {
        Object.defineProperty(that, key, {
            configurable: true,
            enumerable: true,
            get: function proxyGetter () {
                return that._data[key];
            },
            set: function proxySetter (val) {
                that._data[key] = val;
            }
        })
    });
}

我们就可以用 app.text 代替 app._data.text 了。

  • Vue.js

    Vue.js(读音 /vju ː/,类似于 view)是一个构建数据驱动的 Web 界面库。Vue.js 的目标是通过尽可能简单的 API 实现响应的数据绑定和组合的视图组件。

    265 引用 • 666 回帖
  • 前端

    前端技术一般分为前端设计和前端开发,前端设计可以理解为网站的视觉设计,前端开发则是网站的前台代码实现,包括 HTML、CSS 以及 JavaScript 等。

    247 引用 • 1348 回帖
  • JavaScript

    JavaScript 一种动态类型、弱类型、基于原型的直译式脚本语言,内置支持类型。它的解释器被称为 JavaScript 引擎,为浏览器的一部分,广泛用于客户端的脚本语言,最早是在 HTML 网页上使用,用来给 HTML 网页增加动态功能。

    728 引用 • 1273 回帖

相关帖子

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...
  • https://hacpai.com/article/1499135118665 上次为了解答这个问题,也是看了一早上

    1 回复
  • answershuto
    作者

    哈哈

  • zonghua

    前些天面试,面试官直接问我怎么自己实现一个 MVVM,直接往深入问

    1 回复
  • answershuto
    作者

    深入问了些啥?

    1 回复
  • zonghua

    怎么实现脏检查,什么更新数据。

    1 回复
  • answershuto
    作者

    据说了解 angular 的数据绑定是根据脏检查实现的,没仔细学习过,最基础的脏检查就是起个线程(假装有线程的概念)轮训检查数据是否改变,当然 ng 不会那么 low 的,我猜测是在事件等改变的时候才会去检查,果断时间可以学习研究下 ~

请输入回帖内容 ...