日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 前端技术 > vue >内容正文

vue

vue取通过key取value_彻底理解Vue中的Watcher、Observer、Dep

發(fā)布時(shí)間:2025/3/15 vue 28 豆豆
生活随笔 收集整理的這篇文章主要介紹了 vue取通过key取value_彻底理解Vue中的Watcher、Observer、Dep 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

思考以下代碼

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 = null

Observer 類 主要做了以下事情

  • 遍歷 data 下的每一個(gè)屬性,若是對象,則 執(zhí)行 new Observer() ,在對象上新增__ob__屬性,該屬性的值為 Observer 的實(shí)例
  • 劫持對象屬性的變化,在 getter 的時(shí)候,拿到 Observer 實(shí)例的dep實(shí)例,執(zhí)行dep.depend(),代碼如下
  • const ob = this.__ob__ob.dep.depend();

    看下 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)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。