vue 响应式机制简述

先思考一个问题?

如何让变量b的值是a的10倍:

let a = 3
let b = a * 10
console.log(b) // 30

但是如果当a不断变换,b并不会随着a的变换而变化,因为它是命令式的,并不存在同步关系;

let a = 3
let b = a * 10
console.log(b) // 30
a = 4
b = a * 10
console.log(b) // 40

1.数据劫持

那如何让他们俩保持同步呢?

这里就关系到Object.defineProperty这个方法。

对obj的属性foo进行读写操作的劫持

const obj = {
	foo: 123
}

let internalValue = obj.foo

Object.defineProperty(obj,'foo',{
	get(){// 获取obj.foo时触发
    	console.log('get---触发')
		return internalValue
	},
	set(newValue){// 更改obj.foo时触发
    	console.log('set---触发')
		const isChanged = internalValue !== newValue
		if (isChanged) {
			internalValue = newValue
		}
	}
})

// obj.foo
// obj.foo = 456

接下来改造代码封装函数,对obj所有属性设置getter和setter(劫持属性)


function isObject (obj) {
    return typeof obj === 'object'
      && !Array.isArray(obj)
      && obj !== null
      && obj !== undefined
}

function observe(obj){
	if (!isObject(obj)) {
    throw new TypeError()
  }
	
  Object.keys(obj).forEach((key)=>{
      let internalValue = obj[key]
          Object.defineProperty(obj,key,{
              get(){
                  return internalValue
              },
              set(newValue){
                  const isChanged = internalValue !== newValue
                  if (isChanged) {
                      internalValue = newValue
                  }
              }
          })
  })
}

const state = {
	count:0
}

observe(state)

以上做到了对对象所有的属性进行了劫持,接下来对于这个劫持能联系到什么呢

2.依赖收集

先来理解什么是依赖?

  • 先创建一个Dep的类,这个类有两个方法depend()和notify()
  • depend表示当前正在执行的代码,收集这种依赖
  • notify表示依赖发生改变,任何并定义为依赖的表达式、计算、函数都会被通知重新执行

找到一种让他们创建关联的方式,可能是函数、表达式或者计算,那这样的计算关系方式叫做依赖,也被认为是订阅者模式

接下来写一个autorun函数,它可以接受一个更新函数

当进入更新函数的时候,一切就变得很特别,当处于这个响应式空间时,就可以注册依赖

class Dep{
	constructor(){
		this.subscribers = new Set()
	}
	depend(){//订阅
		if(activeUpadte){
			this.subscribers.add(activeUpadte) //2.1 添加订阅
		}
	}
	notify(){//通知
		this.subscribers.forEach(upade=>upade())
	}
}

let dep = new Dep()
let activeUpadte

function autorun(upade){
	function wrappedUpade(){
		activeUpadte = wrappedUpade //1.放到全局变量,以便外部访问
        // 这里可以添加些当依赖发生变化的执行与否的条件
		upade()
		activeUpadte = null
	}
	wrappedUpade()
}

autorun(()=>{
	// 此时 dep中可以处理activeUpadte
	dep.depend()//2.加入依赖
	console.log('---Upade')
})

// dep.notify()

3.迷你观察者

将以上的例子联系起来,在对数据设置getter和setter的时候,分别depend加入订阅和notify通知订阅
Vue的响应式机制完整代码就如下:

class Dep{
	constructor(){
		this.subscribers = new Set()
	}
	depend(){
		if(activeUpadte){
			this.subscribers.add(activeUpadte)
		}
	}
	notify(){
		this.subscribers.forEach(upade=>upade())
	}
}

let activeUpadte

function isObject (obj) {
    return typeof obj === 'object'
      && !Array.isArray(obj)
      && obj !== null
      && obj !== undefined
}

function observe(obj){
	if (!isObject(obj)) {
      throw new TypeError()
    }
	
	Object.keys(obj).forEach((key)=>{
		let internalValue = obj[key]
		let dep = new Dep()
			Object.defineProperty(obj,key,{
				get(){
					dep.depend()//订阅
					return internalValue
				},
				set(newValue){
					const isChanged = internalValue !== newValue
					if (isChanged) {
						internalValue = newValue
						dep.notify()//通知
					}
				}
			})
	})
}

function autorun(upade){
	function wrappedUpade(){
		activeUpadte = wrappedUpade //放入全局依赖
		upade()
		activeUpadte = null
	}
	wrappedUpade()
}

const state = {
	count:0,
	status:true
}

// 做成响应式
observe(state) 

// 依赖跟踪
autorun(()=>{
	//依赖状态变化
	console.log('---',state.count)
})

state.count++

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值