学习笔记 :Vue源码系列(一)

本文详细介绍了Vue.js中数据驱动视图的概念,通过Object.defineProperty实现数据的可观测性,以及Observer类如何将对象转化为响应式。通过对属性的get和set拦截,实现变化侦测,确保视图与数据同步更新。Vue的变化侦测机制与其他前端框架如Angular和React的实现方式进行了对比。
摘要由CSDN通过智能技术生成

总所周知,Vue最大的特点之一就是数据驱动视图,在这里,我们可以把数据理解为状态,而视图就是用户可直观看到页面。页面不可能是一成不变的,它应该是动态变化的,而它的变化也不应该是无迹可寻的,它或者是由用户操作引起的,亦或者是由后端数据变化引起的,不管它是什么引起的,我们统称为它的状态变了,它由前一个状态变到了后一个状态,页面也就应该随之变化,我们把这种特性称之为数据驱动视图。

变化侦测
变化侦测是追踪状态,亦或者说是数据的变化,一旦发生了变化,就去更新视图。
变化侦测可不是个新名词,它在目前的前端三大框架中均有涉及。在Angular中是通过脏值检查流程来实现变化侦测;在React是通过对比虚拟DOM来实现变化侦测,而在Vue中也有自己的一套变化侦测实现机制。

要想知道数据什么时候被读取了或数据什么时候被改写了,其实不难,JS为我们提供了Object.defineProperty方法,通过该方法我们就可以轻松的知道数据什么时候发生变化。

使Object数据变得“可观测”
数据的每次读和写能够被我们看的见,即我们能够知道数据什么时候被读取了或数据什么时候被改写了,我们将其称为数据变的“可观测”。

首先我们定义一个数据对象car:

let car ={
	'brand':'BMW',
	'price':3000
}

接下来,我们使用Object.defineProperty()改写上面的例子:

let car ={}
let val = 3000
Object.defineProperty(car,'price',{
	enumerable: true,
	configurable: true,
	get(){
		console.log('price属性被读取了')
		return val
	}set(newVal){
		console.log('price属性被修改了')
		val = newVal
	}
})

通过Object.defineProperty()方法给car定义了一个price属性,并把这个属性的读和写分别使用get() 和set()进行拦截,每当该属性进行读或写操作的时候就会触发get()和set()。
在这里插入图片描述
可以看到,car已经可以主动告诉我们它的属性的读写情况了,这也意味着,这个car的数据对象已经是“可观测”的了。

/**
 * Observer类会通过递归的方式把一个对象的所有属性都转化成可观测对象
 */
export class Observer {
  constructor (value) {
    this.value = value
    // 给value新增一个__ob__属性,值为该value的Observer实例
    // 相当于为value打上标记,表示它已经被转化成响应式了,避免重复操作
    def(value,'__ob__',this)
    if (Array.isArray(value)) {
      // 当value为数组时的逻辑
      // ...
    } else {
      this.walk(value)
    }
  }

  walk (obj: Object) {
    const keys = Object.keys(obj)
    for (let i = 0; i < keys.length; i++) {
      defineReactive(obj, keys[i])
    }
  }
}
/**
 * 使一个对象转化成可观测对象
 * @param { Object } obj 对象
 * @param { String } key 对象的key
 * @param { Any } val 对象的某个key的值
 */
function defineReactive (obj,key,val) {
  // 如果只传了obj和key,那么val = obj[key]
  if (arguments.length === 2) {
    val = obj[key]
  }
  if(typeof val === 'object'){
      new Observer(val)
  }
  Object.defineProperty(obj, key, {
    enumerable: true,
    configurable: true,
    get(){
      console.log(`${key}属性被读取了`);
      return val;
    },
    set(newVal){
      if(val === newVal){
          return
      }
      console.log(`${key}属性被修改了`);
      val = newVal;
    }
  })
}

在上面的代码中,我们定义了observer类,它用来将一个正常的object转换成可观测的object。
并且给value新增一个_ob_属性,值为该value的Observer实例。这个操作相当于为value打上标记,表示它已经被转化成响应式了,避免重复操作。
然后判断数据的类型,只有object类型的数据才会调用walk将每一个属性转换成getter/setter的形式来侦测变化。最后,在defineReactive中当传入的属性值还是一个object时使用new objectserver(val)来递归子属性,这样我们就可以把obj中的所有属性(包括子属性)都转换成getter/setter的形式来侦测变化。也就是说,只要我们将一个object传到observer中,那么这个object就会变成可观测的、响应式的object。

那么接下来就可以这样定义car:

let car = new Observer({
	'brand':'BMW',
	'price':3000
})

这样,car的两个属性都变得可观测了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值