【Vue原理】响应式原理

响应式系统

  • 我们都知道,只要在 Vue 实例中声明过的数据,那么这个数据就是响应式的。
  • 什么是响应式,也即是说,数据发生改变的时候,视图会重新渲染,匹配更新为最新的值。
  • 也正是因为这个系统,让我们可以脱离界面的束缚,只需要操作数据

我们可以问出下面三个问题

1、Vue 是怎么知道数据改变?
2、Vue 在数据改变时,怎么知道通知哪些视图更新?
3、Vue 在数据改变时,视图怎么知道什么时候更新?

问题的谜底将在下面一一解开

现在,我将会讲解三个重要的概念
1、Object.defineProperty
2、依赖收集
3、依赖更新

1、Object.defineProperty

这个方法,是 Vue 响应式系统的精髓,骨髓,脑髓

使用 Object.defineProperty 可以为对象中的每一个属性,设置 get 和 set 方法

Object.defineProperty 可以为属性设置很多特性,例如 configurable,enumerable,但是现在不过多解释,重点只放在 get 和 set

那么 get 和 set 方法有什么用?

get 值是一个函数,当属性被访问时,会触发 get 函数

set 值同样是一个函数,当属性被赋值时,会触发 set 函数

举个例子

var obj={    
    name:"刘亦菲"
}
Object.defineProperty(obj,"name",{
    get(){        
        console.log("get 被触发")
    },
    set(val){        
        console.log("set 被触发")
    }
})

当我访问 obj.name 时,会打印 'get 被触发 '

当我为 obj.name 赋值时,obj.name = 5,会打印 'set 被触发 '

这便可以回答了我开篇的第一个问题

Vue 是怎么知道数据改变的呢?

恩,Vue 在 属性的 set 方法中做了手脚,因而当数据改变时,触发 属性的 set 方法,Vue 就能知道数据有改变

2、依赖收集

简单地说

data 中的声明的每个属性,都拥有一个数组,保存着 谁依赖(使用)了它

举个例子

new Vue({    
    data(){        
        return {            
            name:"神仙朱"        
        }    
    }
})

然后 页面A 引用了name

<div>{{name}}</div>

此时,name 把 页面 A 存在它的后宫中(这个页面依赖我)

为什么呢?

因为它知道谁依赖它之后,它就可以在发生改变的时候,通知 依赖它的页面,从而让页面完成更新

TIP

实际上,会依赖 name 的地方,不只是页面,还会有 computed,watch.... 等等,但是这里我们全部使用页面一词替代

这就是依赖收集,把 依赖了我(使用了我的东西),统统保存起来。
可是,保存在哪里,具体保存的是什么东西,我们这里暂时不深入,因为这是白话文。
我按上面的例子,从Vue 内部打印一份数据供大家简单了解即可

微信图片_20191212153514.jpg

可以看到,name 属性,使用了 一个 dep 保存了 页面A 这个依赖,而保存的实际上是 页面A的 Watcher。

TIP
简单说一下,watcher 是什么,每个 Vue 实例都会拥有一个专属的 watcher,可用于实例更新

总结一下

1、data 中每个声明的属性,都会有一个 专属的依赖收集器 subs
2、当页面使用到 某个属性时,页面的 watcher 就会被 放到 依赖收集器 subs 中

数据 是在什么时候进行 收集依赖 的呢?

答案是,ObjectdefineProperty - get
当 页面 A 读取了 name 时,会触发 name 的 get 函数,此时,name 就会保存 页面A 的 watcher 啦!

这便可以回答了我开篇的第二个问题

Vue 在数据改变时,怎么知道通知哪些视图更新?

恩,通知那些存在 依赖收集器中的 视图

3、依赖更新

依赖更新,就是,通知所有的依赖进行更新
经过上面的讲解,我们都知道,每个属性都会保存有一个 依赖收集器 subs
而这个 依赖收集器,是用来在 数据变化时,通知更新的

数据 是在 什么时候进行 依赖更新 的呢?

答案是,Object.defineProperty - set
以上面的 Vue 实例 为例
当 name 改变的时候,name 会遍历自己的 依赖收集器 subs,逐个通知 watcher,让 watcher 完成更新
这里 name 会通知 页面A,页面A 重新读取新的 name ,然后完成渲染

这便可以回答了我开篇的第二个问题

Vue 在数据改变时,视图怎么知道什么时候更新?

恩,在数据变化触发 set 函数时,通知视图,视图开始更新

3、简单总结

1、Object.defineProperty - get ,用于 依赖收集
2、Object.defineProperty - set,用于 依赖更新
3、每个 data 声明的属性,都拥有一个的专属依赖收集器 subs
4、依赖收集器 subs 保存的依赖是 watcher
5、watcher 可用于 进行视图更新

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,684评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,143评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,214评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,788评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,796评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,665评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,027评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,679评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,346评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,664评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,766评论 1 331
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,412评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,015评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,974评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,203评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,073评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,501评论 2 343