vue是如何實(shí)現(xiàn)computed實(shí)時(shí)計(jì)算

1、vue雙向數(shù)據(jù)綁定原理圖


132184689-57b310ea1804f_articlex.png

2、基礎(chǔ)補(bǔ)充

(1)Object.keys(obj) :作用:獲取對(duì)象的所有屬性,返回屬性數(shù)組

     let obj = {
    a:12,
    b:'abc',
    c:['a','b']
    }
  let keys = Object.keys(obj)
  console.log(keys)
  //結(jié)果:["a","b","c"]
  //獲取對(duì)象的值
  keys.forEach((key) => {
   keys.forEach((key) => {
  console.log( 'key='+key, 'value='+obj[key])  
})
//結(jié)果:
//key=a value=12
//key=b value=abc
//key=c value=a,b
Object.keys(obj).png

(2)Object.defineProperty(obj,prop,descriptor) 方法會(huì)直接在一個(gè)對(duì)象上定義一個(gè)新屬性,或者修改一個(gè)對(duì)象的現(xiàn)有屬性, 并返回這個(gè)對(duì)象。在vue中可以理解為:使用這個(gè)方法使對(duì)象變得“可觀測(cè)”

參數(shù)

obj
要在其上定義屬性的對(duì)象。
prop
要定義或修改的屬性的名稱。
descriptor
將被定義或修改的屬性描述符。

返回值

被傳遞給函數(shù)的對(duì)象。

     let obj = {
      a:12,
      b:'abc',
      c:['a','b']
      }
    let val = 2000;
    let key ='a';
Object.defineProperty(obj,key, {
    get(){
        console.log('我的屬性值被讀取了='+key)
        return val
        },
    set(newValue){
        console.log('我的屬性被修改了='+newValue);
        return newValue 
    }
})
//默認(rèn)情況下,會(huì)先執(zhí)行g(shù)et函數(shù),當(dāng)屬性值發(fā)生變化,才會(huì)執(zhí)行set函數(shù),再執(zhí)行g(shù)et函數(shù)
Object.defineProperty.png

(2)實(shí)現(xiàn)代碼

一、使數(shù)據(jù)對(duì)象變得“可觀測(cè)”

/**
 * 使一個(gè)對(duì)象轉(zhuǎn)化成可觀測(cè)對(duì)象
 * @param { Object } obj 對(duì)象
 * @param { String } key 對(duì)象的key
 * @param { Any } val 對(duì)象的某個(gè)key的值
 */
function defineReactive (obj, key, val) {
      Object.defineProperty(obj,key, {
    get(){
        console.log('我的屬性值被讀取了='+key)
        return val
        },
    set(newValue){
        console.log('我的屬性被修改了='+newValue);
        return newValue 
    }
    })
}
/**
 * 把一個(gè)對(duì)象的每一項(xiàng)都轉(zhuǎn)化成可觀測(cè)對(duì)象
 * @param { Object } obj 對(duì)象
 */
function observable (obj) {
    const keys = Object.keys(obj);
    keys.forEach((key) =>{
         defineReactive(obj, key,obj[key])
    })
   return obj;
}

//現(xiàn)在我們可以把英雄這么定義:  
const obj1= observable({
  a: 3000,
  b: 150
})


使數(shù)據(jù)對(duì)象變得“可觀測(cè)”.png

二、依賴收集
目的:讓對(duì)象主動(dòng)發(fā)出通知的功能
思路:當(dāng)可觀測(cè)對(duì)象的屬性被讀寫時(shí),就會(huì)觸發(fā)getter和seter方法,可以在geter和seter方法,去執(zhí)行監(jiān)聽器里面的onComputedUpdate()方法,由于onComputedUpdate()需要接收回到函數(shù)的返回值作為參數(shù),而可觀測(cè)對(duì)象中并沒有回調(diào)函數(shù),所以需要一個(gè)能夠收集監(jiān)聽器內(nèi)的回調(diào)函數(shù)的值以及onComputedUpdate()方法的依賴收集器

/**
 * 定義一個(gè)“依賴收集器”
 */
const Dep = {
  target: null
}

/**
 * 使一個(gè)對(duì)象轉(zhuǎn)化成可觀測(cè)對(duì)象
 * @param { Object } obj 對(duì)象
 * @param { String } key 對(duì)象的key
 * @param { Any } val 對(duì)象的某個(gè)key的值
 */
function defineReactive (obj, key, val) {
  const deps = []
  Object.defineProperty(obj, key, {
    get () {
      console.log(`我的${key}屬性被讀取了!`)
      if (Dep.target && deps.indexOf(Dep.target) === -1) {
        deps.push(Dep.target)
      }
      return val
    },
    set (newVal) {
      console.log(`我的${key}屬性被修改了!`)
      val = newVal
      deps.forEach((dep) => {
        dep()
      })
    }
  })
}

/**
 * 把一個(gè)對(duì)象的每一項(xiàng)都轉(zhuǎn)化成可觀測(cè)對(duì)象
 * @param { Object } obj 對(duì)象
 */
function observable (obj) {
  const keys = Object.keys(obj)
  for (let i = 0; i < keys.length; i++) {
    defineReactive(obj, keys[i], obj[keys[i]])
  }
  return obj
}

/**
 * 當(dāng)計(jì)算屬性的值被更新時(shí)調(diào)用
 * @param { Any } val 計(jì)算屬性的值
 */
function onComputedUpdate (val) {
  console.log(`我的類型是:${val}`)
}

/**
 * 觀測(cè)者
 * @param { Object } obj 被觀測(cè)對(duì)象
 * @param { String } key 被觀測(cè)對(duì)象的key
 * @param { Function } cb 回調(diào)函數(shù),返回“計(jì)算屬性”的值
 */
function watcher (obj, key, cb) {
  // 定義一個(gè)被動(dòng)觸發(fā)函數(shù),當(dāng)這個(gè)“被觀測(cè)對(duì)象”的依賴更新時(shí)調(diào)用
  const onDepUpdated = () => {
    const val = cb()
    onComputedUpdate(val)
  }

  Object.defineProperty(obj, key, {
    get () {
      Dep.target = onDepUpdated
      // 執(zhí)行cb()的過程中會(huì)用到Dep.target,
      // 當(dāng)cb()執(zhí)行完了就重置Dep.target為null
      const val = cb()
      Dep.target = null
      return val
    },
    set () {
      console.error('計(jì)算屬性無(wú)法被賦值!')
    }
  })
}

const obj= observable({
  a: 3000,
  b: 150
})

watcher(obj, 'd', () => {
  return obj.a > 1000 ? '坦克' : '脆皮'
})

result.png
參考文章

參考鏈接1
參考鏈接2

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容