美文网首页Vue
vue是如何实现computed实时计算

vue是如何实现computed实时计算

作者: 落花夕拾 | 来源:发表于2019-08-14 14:56 被阅读0次

1、vue双向数据绑定原理图


132184689-57b310ea1804f_articlex.png

2、基础补充

(1)Object.keys(obj) :作用:获取对象的所有属性,返回属性数组

     let obj = {
    a:12,
    b:'abc',
    c:['a','b']
    }
  let keys = Object.keys(obj)
  console.log(keys)
  //结果:["a","b","c"]
  //获取对象的值
  keys.forEach((key) => {
   keys.forEach((key) => {
  console.log( 'key='+key, 'value='+obj[key])  
})
//结果:
//key=a value=12
//key=b value=abc
//key=c value=a,b
Object.keys(obj).png

(2)Object.defineProperty(obj,prop,descriptor) 方法会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性, 并返回这个对象。在vue中可以理解为:使用这个方法使对象变得“可观测”

参数

obj
要在其上定义属性的对象。
prop
要定义或修改的属性的名称。
descriptor
将被定义或修改的属性描述符。

返回值

被传递给函数的对象。

     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 
    }
})
//默认情况下,会先执行get函数,当属性值发生变化,才会执行set函数,再执行get函数
Object.defineProperty.png

(2)实现代码

一、使数据对象变得“可观测”

/**
 * 使一个对象转化成可观测对象
 * @param { Object } obj 对象
 * @param { String } key 对象的key
 * @param { Any } val 对象的某个key的值
 */
function defineReactive (obj, key, val) {
      Object.defineProperty(obj,key, {
    get(){
        console.log('我的属性值被读取了='+key)
        return val
        },
    set(newValue){
        console.log('我的属性被修改了='+newValue);
        return newValue 
    }
    })
}
/**
 * 把一个对象的每一项都转化成可观测对象
 * @param { Object } obj 对象
 */
function observable (obj) {
    const keys = Object.keys(obj);
    keys.forEach((key) =>{
         defineReactive(obj, key,obj[key])
    })
   return obj;
}

//现在我们可以把英雄这么定义:  
const obj1= observable({
  a: 3000,
  b: 150
})


使数据对象变得“可观测”.png

二、依赖收集
目的:让对象主动发出通知的功能
思路:当可观测对象的属性被读写时,就会触发getter和seter方法,可以在geter和seter方法,去执行监听器里面的onComputedUpdate()方法,由于onComputedUpdate()需要接收回到函数的返回值作为参数,而可观测对象中并没有回调函数,所以需要一个能够收集监听器内的回调函数的值以及onComputedUpdate()方法的依赖收集器

/**
 * 定义一个“依赖收集器”
 */
const Dep = {
  target: null
}

/**
 * 使一个对象转化成可观测对象
 * @param { Object } obj 对象
 * @param { String } key 对象的key
 * @param { Any } val 对象的某个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()
      })
    }
  })
}

/**
 * 把一个对象的每一项都转化成可观测对象
 * @param { Object } obj 对象
 */
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
}

/**
 * 当计算属性的值被更新时调用
 * @param { Any } val 计算属性的值
 */
function onComputedUpdate (val) {
  console.log(`我的类型是:${val}`)
}

/**
 * 观测者
 * @param { Object } obj 被观测对象
 * @param { String } key 被观测对象的key
 * @param { Function } cb 回调函数,返回“计算属性”的值
 */
function watcher (obj, key, cb) {
  // 定义一个被动触发函数,当这个“被观测对象”的依赖更新时调用
  const onDepUpdated = () => {
    const val = cb()
    onComputedUpdate(val)
  }

  Object.defineProperty(obj, key, {
    get () {
      Dep.target = onDepUpdated
      // 执行cb()的过程中会用到Dep.target,
      // 当cb()执行完了就重置Dep.target为null
      const val = cb()
      Dep.target = null
      return val
    },
    set () {
      console.error('计算属性无法被赋值!')
    }
  })
}

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

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

result.png
参考文章

参考链接1
参考链接2

相关文章

网友评论

    本文标题:vue是如何实现computed实时计算

    本文链接:https://www.haomeiwen.com/subject/tbzfcxtx.html