-
Notifications
You must be signed in to change notification settings - Fork 0
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Vue 源码解析--数据响应化 #1
Comments
厉害了我的哥👍 @ywlvs @ToxinSting |
@ruooooooli 还是不如你全栈强啊 🌝 |
你们都屌的一塌糊涂,就不要挖苦我了
来自 魅蓝 3s
…-------- 原始邮件 --------
发件人:Cong <notifications@github.com>
时间:周二 8月29日 12:05
收件人:pspgbhu/vue-source-analysis <vue-source-analysis@noreply.github.com>
抄送:rayle <leiyisheng81@163.com>,Mention <mention@noreply.github.com>
主题:Re: [pspgbhu/vue-source-analysis] Vue 源码解析--数据响应化 (#1)
@ruooooooli 还是不如你全栈强啊 🌝
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub, or mute the thread.
{"api_version":"1.0","publisher":{"api_key":"05dde50f1d1a384dd78767c55493e4bb","name":"GitHub"},"entity":{"external_key":"github/pspgbhu/vue-source-analysis","title":"pspgbhu/vue-source-analysis","subtitle":"GitHub repository","main_image_url":"https://cloud.githubusercontent.com/assets/143418/17495839/a5054eac-5d88-11e6-95fc-7290892c7bb5.png","avatar_image_url":"https://cloud.githubusercontent.com/assets/143418/15842166/7c72db34-2c0b-11e6-9aed-b52498112777.png","action":{"name":"Open in ***@***.*** in #1: @ruooooooli 还是不如你全栈强啊 🌝"}],"action":{"name":"View Issue","url":"#1 (comment)"}}}
|
胡老板, 带带我.... |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Vue-Source-Code-Analysis
Vue 源码解析是一项庞大的工程,尤其是你想将它写下来时。正因为如此,一个正确的切入点总显得的那么重要,很明显,在 Vue 中 数据响应化起到了挈领提纲的作用,因此我们也将从 Vue 中 数据响应化开始,抽丝剥茧,一层层的掀开 Vue 的神秘面纱。
data 的诞生及代理
上面是我们在 Vue 实例中定义的一组 data,data 的属性值大致可以分为三类,分别是基本类型值,对象和数组。先预告一下, vue 对于数组的处理与基本类型值是不一样的。
Vue 构造函数内部只有一行
this._init(options)
,其中,初始化了各种属性,调用了各种 init 函数。 而其中的this._initState
又是调用了一堆 init ,_initData()
里面做的事情很简单,执行 vue 实例中的 data 函数,并返回一个 data 对象,同时将 data 中每一项代理到 this 上,这也是为什么我们可以直接通过 this[property] 拿到 data 中的值。data 的响应化
不要说你们没有留意到上段代码中的
observe(data, this)
函数(没看到的可以去检查视力了),以下内容均为响应式的关键。observe 函数会对调用 Observer 构造函数对 data 及 data 下的对象和数组属性进行加工,使其成为响应式数据。
observe 函数先对数据进行了检查,如果是基本类型值的话直接返回(若 value 是基本类型值的话,其所属对象一定已经被 Observer 改造过了),此时我们进来的 value 是 vue 实例的 data,因此会通过第一个检查。而后的 if 是判断 value 是否已经被 Observer 改造过?当然此时我们的 data 还没有,因此会进入 else if 中,调用 Observer 构造函数。
Observer 构造函数
上面用一个 if 条件判断将对象和数组进行了分别处理,先来看一下是如果处理对象的。
对象
this.walk(value)
函数的非常简单,就是遍历 value 中的每一项,并对其调用defineReactive(this.value, key, val)
。defineReactive 函数第一个参数就是 Observer 构造函数接受的 value 参数,而后 key 和 val 参数分别为this.walk(value)
遍历的 value 对象的键和值。到这里就很清楚了,vue 实例下 this._data 对象的基本类型属性值会在这里添加存取描述符 get & set, this._data 下的对象值会一级级的递归拆解直到为基本类型值为止,然后再为每一个值定义 getter & setter,以检测变化
数组
OK,现在开始看一下是如何检测数组变动:
以下为 Observer 构造函数判断参数为数组时的执行逻辑
正常情况下,执行数组的七种变异方法(push, pop, splice, sort, reverse, shift, unshift)是无法触发为数组定义的 setter 函数的,因此使用之前的方法是不能够检测的对数组进行的改变的。这里尤大想了一个办法,重新改造了数组的七种变异方法,使数组执行这七种方法的后向上发出通知。这样子的话就不需要 getter 和 setter 去检测数组的每一项的变化了,只要数组调用了以上的七种方法,vue 就会收到通知。但是很明显的是,你只能用这七种方法来操作数组,vue 才能检测到数组的变化。
同时为了避免污染 Array 原生的方法,创建了一个新的对象,保存了改造后的数组原型,让 data 中的数组去继承改造后的数组原型。
但是在 ES5 更早版本的 ES 中没有可靠的继承数组的方法,所以这里就尽可能的利用了 proto 属性。
对于支持 proto 属性的浏览器,直接修改其 proto 属性来使其继承改造后的 Array 原型。而有些浏览器不支持 proto 属性,则去一一的重写 Array 的方法。
以上就是为什么我们只能用 push, pop, splice, sort, reverse, shift, unshift 这七种方法来改变数组。
Thinking
getter 和 setter 用来检测数据的改变非常合适,但是若是直接删除了这个数据呢?这样是不会触发 setter 的,那 Vue 中是如何处理的呢?
Observer 在原型上添加了 dep,definedReactive 在闭包中保存了 dep, 发布者已经找到呢,那订阅者是在哪里订阅的呢?
根据 defineReactive 函数来看,层级较深的对象也是能够检测到其值的变化的,但是为什么在实际使用中却不能直接使用 this.a.b.c = 1 这样的赋值方式呢?
以上的问题留到后面继续解答吧,哈哈!
Reference:
The text was updated successfully, but these errors were encountered: