vue知识点-1--变化侦测-依赖收集

本文相当于笔记,最近在看深入浅出vue.js的记录,需要配合书一起看,如果你也在看这本书可以一起看看这篇文章,不然会看不懂。
vue 在运行是内部的状态不断改变,页面不停的重新渲染,想要达到这样的变化侦测效果第一步就要解决依赖收集的部分。
依赖收集就是记录哪些数据用到了哪些地方,这样在变化的时候就能去精准的通知其去改变。

大体思路就是用Object.defineProperty 设置get、set监听到数据的读取和改变,在get中收集依赖,在set通知收集到的依赖去改变。

Dep收集依赖的地方,可以叫做存储位置

封装一个Dep类管理依赖收集的地方(depend依赖 的缩写,为每个属性都new 一个Dep类,每个属性都有自己对于的依赖收集的地方)
Dep类中 主要的结构
this.subs = [] (subscribe 订阅 缩写)这个数组就是用来收集具体哪里调用的该属性,
depend()函数 push进subs中 就是添加依赖的,判断window.target是否有值 如果有假加入到subs中(window.target)是全局变量
notify()函数 用于更新所有的依赖 里面就是一个循环调用subs的update方法

defineReactive()收集和触发依赖动作

defineReactive() 是个方法 里面封装了 Object.defineProperty 统一设置了get,set为每一个属性,get中收集, set中触发更新

先是调用了observe() 传递进入val
let childOb = observe(val)
这个函数内部判断了是否是对象如果是不是对象就返回空(数组也是对象哦,typeof)
不是对象,有个过滤的机制避免重复侦测,根据__ob__
过滤后调用真正的Observe 该类主要功能是循环对象递归调用defineReactive使其每个属性都具备get,set也就是有收集和触发的功能,Observe是个类 childOb拿到的是他的实例
Observe稍后介绍继续说defineReactive

实例化了let dep = new Dep()

在get中调用了 dep.depend() 以及 childOb.dep.depend()
这么写是为了统一在get中进行依赖收集 childOb 是用来处理 数组的依赖收集,
数组和对象的依赖收集都是一样的 list:[] 要读取这个数组 就要先找到list 肯定会触发list的get
数组的操作方法,push shift 这些改变数组的方法不能触发getter/setter,数组用的是重写覆盖原始的Array原型方法这样就知道了用户操作了那些方法,以这种形式来收集和触发依赖,这也被叫做拦截器

set中调用 dep.notify()

Watcher类 数据变化通知的地方 可以看做vue中的$watch

get()方法 这里很厉害,把this 赋值给全局变量 window.target 然后再去读取对应的数据,这样就触发了上一步写的 defineReactive 中设置好的get get中调用dep.depend(), depend把window.target 加入到 subs数组中,用于以后更改时update,这样就顺利的把前后链接了起来
update()方法 上面说的 notify会循环调用数据的更新就是这里的update方法,该方法里是$watch时写的回调用call保持上下文关系执行,
所以每次声明watch的时候会在constructor中调用this.get(),就可以主动的把this添加到dep中,很神奇。

Observer()递归侦测所有属性

主要用于循环数据下面的所有属性让每个属性都有收集和通知的能力,这其中也处理了数组的原型覆盖,

实例了dep 用于数据依赖收集的

给每个数据加上了一个不可枚举的__ob__标识,这个标识就是this,主要是两个作用,
1、用于过滤判断当前属性是否已经被侦测变化,
2、数组是侦测变化是改写原型上的方法,原型上从this直接拿到__ob__就是Observer的实例,实例上有dep 当触发了改写的push后就能去调用dep 中的notify()
这里很巧妙,收集是在defineReactive的get中 调用是在 原型的方法中,Observer相当于是中间的位置,上下都能拿到

如果是对象就循环递归调用 defineReactive

判断如果是数组重新赋值他的__proto__, __proto__指向的是实例他的原型,也就是一个对象,所以生成一个对象就好,这个对象以Array.prototype作为基础在上面改写,要保证数据传进来调用 Array.prototype 同样的方法做处理,返回同样的返回值,然后在这其中加入收集和通知就ok了,
arrayMethods = Object,creare(Array.prototype);
只改写了push pop shift unshift splice sort reverse 一共七个可以改变自身的方法,
用defineProperty改写,在value中 用 apply保持上下文并且把 ...args传入进去 让其拥有原本的功能并且返回一样的值,
额外的操作 let ob = this.__ob __;这个是Observer的实例,里面有dep,调用dep.notify()让其更新,
如果使用的是push unshift splice 这三,他们是可以在数组中新增元素的,新增的元素要保持可以侦测变化,同样是调用ob上的方法,observeArray

observeArray 循环传递进来的数组,调用observe,又回来了,---是对象就循环递归调用 defineReactive ,是数组覆盖__proto__

以上这些大致就是变化侦测的基本实现

了解了原理也就知道了为什么vue中一些数据的变化是不能更新的。
this.list[0] = 1;
observe 数组中循环时对象通过,否则不会赋予收集和通知的功能。数组中是个值是不能监测变化的是对象可以。
list.length = 0
vue在处理是根本没有这个回调,所以这样使用时都不知道数组变化了。
delete this.obj.name这样的操作是不能追踪变化的,因为defineProperty 的set 只能知道数据是否被更改不能知道数据是否被删除或是新增。不过也有配套的api解决这个问题 vue.set , vue.delete

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