vue取通过key取value_彻底理解Vue中的Watcher、Observer、Dep
思考以下代碼
new Vue({el: '#example',data(){return{obj:{a:1}}}, })當(dāng)我們寫下這行代碼時(shí),vue將我們在data內(nèi)定義的obj對象進(jìn)行依賴追蹤.
具體做法為執(zhí)行new Observer(obj)
//經(jīng)過上面的代碼,我們的obj對象會(huì)變?yōu)橐韵碌臉幼?{obj:{a:1,__ob__:{ //Observer 實(shí)例dep:{Dep 實(shí)例subs:[ //存放 Watcher 實(shí)例new Watcher(),]}}} }我們來一步步實(shí)現(xiàn)看下。 1. 在obj對象上新增__ob__屬性,值為Observe 類的實(shí)例,我們編寫一個(gè) def 函數(shù),用來增加屬性
function def(obj, key, val, enumerable) {Object.defineProperty(obj, key, {value: val,enumerable: !!enumerable,writable: true,configurable: true}); }增加啥屬性呢?之前提到了,我們需要增加一個(gè) Observer 實(shí)例,實(shí)現(xiàn)如下
Observe 實(shí)現(xiàn)
class Observer {constructor(targetObject) {def(targetObject, '__ob__', this);//在 targetObject 上 添加 Observer 實(shí)例, setter時(shí) 通知該實(shí)例this.walk(targetObject)this.dep = new Dep()}walk(obj) {Object.keys(obj).forEach(key => {defineReactive(obj, key, obj[key])});}}function observe(data) {if (Object.prototype.toString.call(data) !== '[object Object]') {return}new Observer(data) }function defineReactive(obj, key, val) {observe(val)Object.defineProperty(obj, key, {enumerable: true,configurable: true,get: function reactiveGetter() {console.log('get');const ob = this.__ob__ob.dep.depend();return val},set: function reactiveSetter(newVal) {console.log('set');if (newVal === val) returnval = newValobserve(newVal)const ob = this.__ob__ob.dep.notify();},}) }function def(obj, key, val, enumerable) {Object.defineProperty(obj, key, {value: val,enumerable: !!enumerable,writable: true,configurable: true}); }這里面牽扯到了 Dep,我們也把Dep實(shí)現(xiàn)下,
Dep
class Dep {constructor() {this.subs = []}addSub(sub) {this.subs.push(sub)}depend() {this.subs.push(Dep.target)}notify() {for (let i = 0; i < this.subs.length; i++) {this.subs[i].fn()}} }Dep.target = nullObserver 類 主要做了以下事情
看下 dep.depend()做了些啥
this.subs.push(Dep.target)將Dep.target添加到 訂閱數(shù)組內(nèi)(this.subs)
也就是說,只要我們 Dep.target 賦值了,再執(zhí)行 dep.depend(),那么該值就會(huì)被添加到 dep 的 subs 數(shù)組內(nèi),比如Dep.target =function test(){} dep.depend() // test 函數(shù)就算 Dep 的訂閱者了實(shí)現(xiàn)自動(dòng)添加依賴
這個(gè)時(shí)候該 Watcher出場了
Watcher 實(shí)現(xiàn)
const Dep = require('./Dep')class Watcher {constructor(vm, exp, fn) {this.vm = vmthis.exp = expthis.fn = fnDep.target = this//將自己掛載到 Dep.target,調(diào)用 Dep.depend時(shí)會(huì)讀取該變量this.vm[exp]} }module.exports = Watcher根據(jù)一個(gè)小例子來理解 Watcher
const obj = {a: 1,b: {c: 2} }new Observer(obj) new Watcher(obj, 'a', () => {console.log('Watcher 回調(diào)執(zhí)行') }) obj.a='222'流程如下: 1. 先觀測 obj 對象(new Observer(obj)) 2. 實(shí)例化Watcher時(shí),會(huì)執(zhí)行Dep.target = this,然后執(zhí)行this.vm[exp],也就是取一次值,那么會(huì)觸發(fā) getter,將自身(Watcher實(shí)例)添加到dep的訂閱者數(shù)組內(nèi)
get: function reactiveGetter() {const ob = this.__ob__ob.dep.depend();return val},最后,改變數(shù)據(jù)時(shí)候,觸發(fā)setter
set: function reactiveSetter(newVal) {if (newVal === val) returnval = newValobserve(newVal)const ob = this.__ob__ob.dep.notify();},執(zhí)行ob.dep.notify()
notify() {for (let i = 0; i < this.subs.length; i++) {this.subs[i].fn()}遍歷 訂閱者(subs)執(zhí)行回調(diào)函數(shù),整個(gè)流程結(jié)束
Leeesin/learn-vue-source-code?github.com總結(jié)
以上是生活随笔為你收集整理的vue取通过key取value_彻底理解Vue中的Watcher、Observer、Dep的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: html富文本编辑器插件_vue中使用v
- 下一篇: js文件里获取路由 vue_【源码拾遗】