国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

Vue3響應(yīng)式原理 私

這篇具有很好參考價(jià)值的文章主要介紹了Vue3響應(yīng)式原理 私。希望對(duì)大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請(qǐng)大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問。

響應(yīng)式的本質(zhì):當(dāng)數(shù)據(jù)變化后會(huì)自動(dòng)執(zhí)行某個(gè)函數(shù)映射到組件,自動(dòng)觸發(fā)組件的重新渲染。Vue3響應(yīng)式原理 私,Vue3.0X,vue.js,前端,javascript

響應(yīng)式的實(shí)現(xiàn)方式就是劫持?jǐn)?shù)據(jù),Vue3的reactive就是通過Proxy劫持?jǐn)?shù)據(jù),由于劫持的是整個(gè)對(duì)象,所以可以檢測到任何對(duì)象的修改,彌補(bǔ)了2.0的不足。

名詞解釋:

  • **副作用函數(shù):**函數(shù)的執(zhí)行會(huì)直接或間接影響其他函數(shù)的執(zhí)行,這時(shí)我們說函數(shù)產(chǎn)生了副作用。副作用很容易產(chǎn)生,例如一個(gè)函數(shù)修改了全局變量,這其實(shí)也是一個(gè)副作用。
  • targetmap 是一個(gè) weakmap 類型的集合,用來存儲(chǔ)副作用函數(shù),從類型定義可以看出 targetmap的數(shù)據(jù)結(jié)構(gòu)方式:

weakmap 由 target --> map 構(gòu)成
map 由 key --> set 構(gòu)成

  • 其中 weakmap 的鍵是原始對(duì)象 target,weakmap 的值是一個(gè) map 實(shí)例,map 的鍵是原始對(duì)象 target 的 key,map 的值是一個(gè)由副作用函數(shù)組成的 set。
  • effect函數(shù):創(chuàng)建一個(gè)副作用函數(shù),接受兩個(gè)參數(shù),分別是用戶自定義的fn函數(shù)和options 選項(xiàng)。
  • track收集依賴:訪問數(shù)據(jù)的時(shí)候,觸發(fā)get函數(shù),get函數(shù)最核心的部分是執(zhí)行track函數(shù)收集依賴。這其實(shí)是一種懶操作。
  • trigger派發(fā)更新:當(dāng)對(duì)屬性進(jìn)行賦值時(shí),會(huì)觸發(fā)代理對(duì)象的 set 攔截函數(shù)執(zhí)行。
    ?

track函數(shù)收集依賴的實(shí)現(xiàn)


export function track(target: object, type: trackoptypes, key: unknown) {
    // 如果開啟了依賴收集并且有正在執(zhí)行的副作用,則收集依賴
  if (shouldtrack && activeeffect) {
    // 在 targetmap 中獲取對(duì)應(yīng)的 target 的依賴集合
    let depsmap = targetmap.get(target)
    if (!depsmap) {
      // 如果 target 不在 targetmap 中,則將當(dāng)前 target 添加進(jìn) targetmap 中,并將 targetmap 的 value 初始化為 new map()。
      targetmap.set(target, (depsmap = new map()))
    }
    // 從依賴集合中獲取對(duì)應(yīng)的 key 的依賴
    let dep = depsmap.get(key)
    if (!dep) {
      // 如果 key 不存在,將這個(gè) key 作為依賴收集起來,并將依賴初始化為 new set()
      depsmap.set(key, (dep = createdep()))
    }
  // 最后調(diào)用 trackeffects收集副作用函數(shù),將副作用函數(shù)收集到依賴集合depsmap中。
    const eventinfo = __dev__
      ? { effect: activeeffect, target, type, key }
      : undefined
 
    trackeffects(dep, eventinfo)
  }
}

trackeffects 函數(shù)

收集副作用函數(shù),在 trackeffects 函數(shù)中,檢查當(dāng)前正在執(zhí)行的副作用函數(shù) activeeffect 是否已經(jīng)被收集到依賴集合中,如果沒有,就將當(dāng)前的副作用函數(shù)收集到依賴集合中。同時(shí)在當(dāng)前副作用函數(shù)的 deps 屬性中記錄該依賴。

// 收集副作用函數(shù),在 trackeffects 函數(shù)中,檢查當(dāng)前正在執(zhí)行的副作用函數(shù) activeeffect 是否已經(jīng)被收集到依賴集合中,如果沒有,就將當(dāng)前的副作用函數(shù)收集到依賴集合中。同時(shí)在當(dāng)前副作用函數(shù)的 deps 屬性中記錄該依賴。
export function trackeffects(
  dep: dep,
  debuggereventextrainfo?: debuggereventextrainfo
) {
  let shouldtrack = false
  if (effecttrackdepth <= maxmarkerbits) {
    if (!newtracked(dep)) {
      dep.n |= trackopbit // set newly tracked
      shouldtrack = !wastracked(dep)
    }
  } else {
    // full cleanup mode.
    // 如果依賴中并不存當(dāng)前的 effect 副作用函數(shù)
    shouldtrack = !dep.has(activeeffect!)
  }
 
  if (shouldtrack) {
    // 將當(dāng)前的副作用函數(shù)收集進(jìn)依賴中
    dep.add(activeeffect!)
    // 并在當(dāng)前副作用函數(shù)的 deps 屬性中記錄該依賴
    activeeffect!.deps.push(dep)
    if (__dev__ && activeeffect!.ontrack) {
      activeeffect!.ontrack(
        object.assign(
          {
            effect: activeeffect!
          },
          debuggereventextrainfo
        )
      )
    }
  }
}

trigger 派發(fā)更新

對(duì)屬性進(jìn)行賦值時(shí),會(huì)觸發(fā)代理對(duì)象的 set 攔截函數(shù)執(zhí)行,如下面的代碼所示:

const obj = { foo: 1 } 
//通過代理對(duì)象p 訪問 foo 屬性,便會(huì)觸發(fā) set 攔截函數(shù)的執(zhí)行
const p = new proxy(obj, {
  // 攔截設(shè)置操作
  set(target, key, newval, receiver){
    // 如果屬性不存在,則說明是在添加新屬性,否則設(shè)置已有屬性
    const type = object.prototype.hasownproperty.call(target,key) ?  'set' : 'add'    
    // 設(shè)置屬性值
    const res = reflect.set(target, key, newval, receiver)
    // 把副作用函數(shù)從桶里取出并執(zhí)行,將 type 作為第三個(gè)參數(shù)傳遞給 trigger 函數(shù)
    trigger(target,key,type)   
    return res
  }
  // 省略其他攔截函數(shù)
})
 
p.foo = 2

trigger 函數(shù)

根據(jù)target和key, 從targetMap中找到相關(guān)的所有副作用函數(shù)遍歷執(zhí)行一遍。

export function trigger(
  target: object,
  type: triggeroptypes,
  key?: unknown,
  newvalue?: unknown,
  oldvalue?: unknown,
  oldtarget?: map<unknown, unknown> | set<unknown>
) {
//首先檢查當(dāng)前 target 是否有被追蹤,如果從未被追蹤過,即target的依賴未被收集,則不需要執(zhí)行派發(fā)更新,直接返回即可。
  const depsmap = targetmap.get(target)
  // 該 target 從未被追蹤,則不繼續(xù)執(zhí)行
  if (!depsmap) {
    // never been tracked
    return
  }
 
  // 接著創(chuàng)建一個(gè) set 類型的 deps 集合,用來存儲(chǔ)當(dāng)前target的這個(gè) key 所有需要執(zhí)行派發(fā)更新的副作用函數(shù)。
  let deps: (dep | undefined)[] = []
  //接下來就根據(jù)操作類型type 和 key 來收集需要執(zhí)行派發(fā)更新的副作用函數(shù)。
  //如果操作類型是 triggeroptypes.clear ,那么表示需要清除所有依賴,將當(dāng)前target的所有副作用函數(shù)添加到 deps 集合中。
  if (type === triggeroptypes.clear) {
    // collection being cleared
    // trigger all effects for target
    // 當(dāng)需要清除依賴時(shí),將當(dāng)前 target 的依賴全部傳入
    deps = [...depsmap.values()]
  } else if (key === 'length' && isarray(target)) {
    // 處理數(shù)組的特殊情況
    depsmap.foreach((dep, key) => {
      // 如果對(duì)應(yīng)的長度, 有依賴收集需要更新
      if (key === 'length' || key >= (newvalue as number)) {
        deps.push(dep)
      }
    })
  } else {
    // schedule runs for set | add | delete
    // 在 set | add | delete 的情況,添加當(dāng)前 key 的依賴
    if (key !== void 0) {
      deps.push(depsmap.get(key))
    }
 
    // also run for iteration key on add | delete | map.set
    switch (type) {
      case triggeroptypes.add:
        if (!isarray(target)) {
          deps.push(depsmap.get(iterate_key))
          if (ismap(target)) {
            // 操作類型為 add 時(shí)觸發(fā)map 數(shù)據(jù)結(jié)構(gòu)的 keys 方法的副作用函數(shù)重新執(zhí)行
            deps.push(depsmap.get(map_key_iterate_key))
          }
        } else if (isintegerkey(key)) {
          // new index added to array -> length changes
          deps.push(depsmap.get('length'))
        }
        break
      case triggeroptypes.delete:
        if (!isarray(target)) {
          deps.push(depsmap.get(iterate_key))
          if (ismap(target)) {
            // 操作類型為 delete 時(shí)觸發(fā)map 數(shù)據(jù)結(jié)構(gòu)的 keys 方法的副作用函數(shù)重新執(zhí)行
            deps.push(depsmap.get(map_key_iterate_key))
          }
        }
        break
      case triggeroptypes.set:
        if (ismap(target)) {
          deps.push(depsmap.get(iterate_key))
        }
        break
    }
  }
 
  const eventinfo = __dev__
    ? { target, type, key, newvalue, oldvalue, oldtarget }
    : undefined
 
  if (deps.length === 1) {
    if (deps[0]) {
      if (__dev__) {
        triggereffects(deps[0], eventinfo)
      } else {
        triggereffects(deps[0])
      }
    }
  } else {
    const effects: reactiveeffect[] = []
    // 將需要執(zhí)行的副作用函數(shù)收集到 effects 數(shù)組中
    for (const dep of deps) {
      if (dep) {
        effects.push(...dep)
      }
    }
    if (__dev__) {
      triggereffects(createdep(effects), eventinfo)
    } else {
      triggereffects(createdep(effects))
    }
  }
}

triggereffects 函數(shù)

triggereffects 函數(shù)中,遍歷需要執(zhí)行的副作用函數(shù)集合,如果當(dāng)前副作用函數(shù)存在調(diào)度器,則執(zhí)行該調(diào)度器,否則直接執(zhí)行該副作用函數(shù)的 run 方法,執(zhí)行更新。

//triggereffects 函數(shù)中,遍歷需要執(zhí)行的副作用函數(shù)集合,如果當(dāng)前副作用函數(shù)存在調(diào)度器,則執(zhí)行該調(diào)度器,否則直接執(zhí)行該副作用函數(shù)的 run 方法,執(zhí)行更新。
export function triggereffects(
  dep: dep | reactiveeffect[],
  debuggereventextrainfo?: debuggereventextrainfo
) {
  // spread into array for stabilization
  // 遍歷需要執(zhí)行的副作用函數(shù)集合   
  for (const effect of isarray(dep) ? dep : [...dep]) {
    // 如果 trigger 觸發(fā)執(zhí)行的副作用函數(shù)與當(dāng)前正在執(zhí)行的副作用函數(shù)相同,則不觸發(fā)執(zhí)行
    if (effect !== activeeffect || effect.allowrecurse) {
      if (__dev__ && effect.ontrigger) {
        effect.ontrigger(extend({ effect }, debuggereventextrainfo))
      }
      if (effect.scheduler) {
        // 如果一個(gè)副作用函數(shù)存在調(diào)度器,則調(diào)用該調(diào)度器
        effect.scheduler()
      } else {
        // 否則直接執(zhí)行副作用函數(shù)
        effect.run()
      }
    }
  }
}

?ES6? Proxy 方法

const p = new Proxy(person, {        //創(chuàng)建代理
      // 查
      get(target,propName){
          console.log(`有人讀取了p身上的${propName}`)
          return target[propName];  
          //反射
          return Reflect.get(target,propName)
      },
      // 改 增
      set(target, propName, value){
          console.log(`有人修改了p身上的${propName}屬性`);
          target[propName] = value;
      },
      // 刪
      deleteProperty(target, propName){
          console.log(`有人刪除了p身上的${propName}屬性`)
          return delete target[propName];
      },
  });
createReactiveObject

之前說到的createReactiveObject,我們接下來看看createReactiveObject發(fā)生了什么。

返回 proxy

const collectionTypes = new Set<Function>([Set, Map, WeakMap, WeakSet])
function createReactiveObject(
  target: unknown,
  toProxy: WeakMap<any, any>,
  toRaw: WeakMap<any, any>,
  baseHandlers: ProxyHandler<any>,
  collectionHandlers: ProxyHandler<any>
) {
  /* 判斷目標(biāo)對(duì)象是否被effect */
  /* observed 為經(jīng)過 new Proxy代理的函數(shù) */
  let observed = toProxy.get(target) /* { [target] : obseved  } */
  if (observed !== void 0) { /* 如果目標(biāo)對(duì)象已經(jīng)被響應(yīng)式處理,那么直接返回proxy的observed對(duì)象 */
    return observed
  }
  if (toRaw.has(target)) { /* { [observed] : target  } */
    return target
  }
  /* 如果目標(biāo)對(duì)象是 Set, Map, WeakMap, WeakSet 類型,那么 hander函數(shù)是 collectionHandlers 否側(cè)目標(biāo)函數(shù)是baseHandlers */
  const handlers = collectionTypes.has(target.constructor)
    ? collectionHandlers
    : baseHandlers
   /* TODO: 創(chuàng)建響應(yīng)式對(duì)象  */
  observed = new Proxy(target, handlers)
  /* target 和 observed 建立關(guān)聯(lián) */
  toProxy.set(target, observed)
  toRaw.set(observed, target)
  /* 返回observed對(duì)象 */
  return observed
}

Vue3響應(yīng)式內(nèi)部原理_vue3的響應(yīng)式原理_monana6的博客-CSDN博客

vue3.0 響應(yīng)式原理(超詳細(xì))_vue3響應(yīng)式原理_我不是外星人Alien的博客-CSDN博客

【干貨】這次終于把 Vue3 響應(yīng)式原理搞懂了!_傲嬌的koala的博客-CSDN博客

ES6 之 Proxy 介紹_es6 proxy_barnett_y的博客-CSDN博客

vue3.0 響應(yīng)式原理(超詳細(xì))_vue3響應(yīng)式原理_我不是外星人Alien的博客-CSDN博客


?文章來源地址http://www.zghlxwxcb.cn/news/detail-686257.html

到了這里,關(guān)于Vue3響應(yīng)式原理 私的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場。本站僅提供信息存儲(chǔ)空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請(qǐng)注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請(qǐng)點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • Vue3響應(yīng)式原理 私

    Vue3響應(yīng)式原理 私

    響應(yīng)式的本質(zhì):當(dāng)數(shù)據(jù)變化后會(huì)自動(dòng)執(zhí)行某個(gè)函數(shù)映射到組件,自動(dòng)觸發(fā)組件的重新渲染。 響應(yīng)式的實(shí)現(xiàn)方式就是劫持?jǐn)?shù)據(jù),Vue3的reactive就是通過Proxy劫持?jǐn)?shù)據(jù),由于劫持的是整個(gè)對(duì)象,所以可以檢測到任何對(duì)象的修改,彌補(bǔ)了2.0的不足。 名詞解釋: **副作用函數(shù):**函數(shù)的

    2024年02月10日
    瀏覽(20)
  • 手寫Vue3響應(yīng)式數(shù)據(jù)原理

    手寫Vue3響應(yīng)式數(shù)據(jù)原理

    我們想要對(duì)一個(gè)對(duì)象數(shù)據(jù)進(jìn)行處理,從而實(shí)現(xiàn)更改dom。但如何更改對(duì)一個(gè)對(duì)象數(shù)據(jù)進(jìn)行更改呢? vue2 的雙向數(shù)據(jù)綁定是利?ES5 的?個(gè) API ,Object.defineProperty()對(duì)數(shù)據(jù)進(jìn)?劫持 結(jié)合 發(fā)布訂閱模式的?式來實(shí)現(xiàn)的。 vue3 中使?了 ES6 的 ProxyAPI 對(duì)數(shù)據(jù)代理,通過 reactive() 函數(shù)給每?

    2024年02月11日
    瀏覽(19)
  • 前端Vue篇之Vue3響應(yīng)式:Ref和Reactive

    在Vue3中,響應(yīng)式編程是非常重要的概念,其中 Ref 和 Reactive 是兩個(gè)關(guān)鍵的API。 Ref : Ref 用于創(chuàng)建一個(gè)響應(yīng)式的基本數(shù)據(jù)類型,比如數(shù)字、字符串等。它將普通的數(shù)據(jù)變成響應(yīng)式數(shù)據(jù),可以監(jiān)聽數(shù)據(jù)的變化。使用 Ref 時(shí),我們可以通過 .value 來訪問和修改數(shù)據(jù)的值。 Reactive :

    2024年04月25日
    瀏覽(25)
  • Vue3.0中的響應(yīng)式原理

    Vue3.0中的響應(yīng)式原理

    實(shí)現(xiàn)原理: - 對(duì)象類型:通過 ``Object.defineProperty()``對(duì)屬性的讀取、修改進(jìn)行攔截(數(shù)據(jù)劫持)。 - 數(shù)組類型:通過重寫更新數(shù)組的一系列方法來實(shí)現(xiàn)攔截。(對(duì)數(shù)組的變更方法進(jìn)行了包裹)。 存在問題: - 新增屬性、刪除屬性, 界面不會(huì)更新。 - 直接通過下標(biāo)修改數(shù)組, 界面

    2023年04月17日
    瀏覽(25)
  • 【Vue3響應(yīng)式原理#01】Reactivity

    【Vue3響應(yīng)式原理#01】Reactivity

    專欄分享:vue2源碼專欄,vue3源碼專欄,vue router源碼專欄,玩具項(xiàng)目專欄,硬核??推薦?? 歡迎各位ITer關(guān)注點(diǎn)贊收藏?????? 以下是柏成根據(jù)Vue3官方課程整理的響應(yīng)式書面文檔 - 第一節(jié),課程鏈接在此:Vue 3 Reactivity - Vue 3 Reactivity | Vue Mastery,本文檔可作為課程的輔助材料,

    2024年02月08日
    瀏覽(17)
  • Vue2和Vue3響應(yīng)式原理實(shí)現(xiàn)的核心

    Vue.js 是一個(gè)開源的漸進(jìn)式 JavaScript 前端框架,主要用于構(gòu)建用戶界面和單頁應(yīng)用程序(SPA)。Vue.js 可以輕松地與其他庫或現(xiàn)有項(xiàng)目集成使用,并被認(rèn)為是開發(fā)響應(yīng)式數(shù)據(jù)驅(qū)動(dòng)的現(xiàn)代 Web 應(yīng)用的一種有效方式。 Vue.js 的核心特點(diǎn): 響應(yīng)式數(shù)據(jù)綁定:Vue.js 可以通過對(duì)數(shù)據(jù)進(jìn)行雙

    2024年02月08日
    瀏覽(39)
  • 【源碼系列#05】Vue3響應(yīng)式原理(Ref)

    ref: 接受一個(gè)參數(shù)值并返回一個(gè)響應(yīng)式且可改變的 ref 對(duì)象。ref 對(duì)象擁有一個(gè)指向內(nèi)部值的單一屬性 .value 可以將 ref 看成 reactive 的一個(gè)變形版本,這是由于 reactive 內(nèi)部采用 Proxy 來實(shí)現(xiàn),而 Proxy 只接受對(duì)象作為入?yún)?,這才有了 ref 來解決值類型的數(shù)據(jù)響應(yīng), 如果傳入 ref 的

    2024年02月03日
    瀏覽(61)
  • 【源碼系列#01】vue3響應(yīng)式原理(Proxy)

    專欄分享:vue2源碼專欄,vue3源碼專欄,vue router源碼專欄,玩具項(xiàng)目專欄,硬核??推薦?? 歡迎各位ITer關(guān)注點(diǎn)贊收藏?????? 在學(xué)習(xí) Vue3 是如何進(jìn)行對(duì)象的響應(yīng)式代理之前,我想我們應(yīng)該先去了解下 ES6 新增的API Proxy 與 Reflect ,可參考【Vue3響應(yīng)式入門#02】Proxy and Reflect 。之

    2024年02月05日
    瀏覽(27)
  • 【源碼系列#02】Vue3響應(yīng)式原理(Effect)

    【源碼系列#02】Vue3響應(yīng)式原理(Effect)

    專欄分享:vue2源碼專欄,vue3源碼專欄,vue router源碼專欄,玩具項(xiàng)目專欄,硬核??推薦?? 歡迎各位ITer關(guān)注點(diǎn)贊收藏?????? Vue3中響應(yīng)數(shù)據(jù)核心是 reactive , reactive 的實(shí)現(xiàn)是由 proxy 加 effect 組合 ,上一章節(jié)我們利用 proxy 實(shí)現(xiàn)了一個(gè)簡易版的 reactive,# 【源碼系列#01】Vue3響應(yīng)

    2024年02月05日
    瀏覽(23)
  • vue2、vue3、react響應(yīng)式原理、組件聲明周期闡述與對(duì)比

    響應(yīng)式原理: Vue.js 的響應(yīng)式原理是通過使用 Object.defineProperty 函數(shù)來實(shí)現(xiàn)的。在 Vue.js 中,當(dāng)一個(gè)對(duì)象被傳入 Vue 實(shí)例的 data 選項(xiàng)中時(shí),Vue.js 會(huì)將這個(gè)對(duì)象的屬性轉(zhuǎn)換為 getter 和 setter,以便在屬性被訪問或修改時(shí)能夠觸發(fā)相應(yīng)的更新。 具體來說,Vue.js 會(huì)在實(shí)例化過程中遞歸

    2024年02月06日
    瀏覽(22)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請(qǐng)作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包