响应式原理实现

350 阅读4分钟

响应式原理实现

响应式函数的封装

// 将需要响应执行的函数添加到数组中
let reactiveFns = []
function watchFn(fn) {
  reactiveFns.push(fn)
}

const obj = {
  name: 'Fhup',
  age: 18
}

watchFn(function obj1Fn(){
  console.log(obj.name);
})

watchFn(function obj2Fn(){
  const newName = obj.name
  console.log(newName);
})


obj.name = 123

reactiveFns.forEach(fn => {
  fn()
})

依赖收集类的封装

class Depend {
  constructor() {
    this.reactiveFns = []
  }
  addDepend(fn) {
    this.reactiveFns.push(fn)
  }
  notify() {
    this.reactiveFns.forEach(fn => {
      fn()
    })
  }
}

const depend = new Depend()
function watchFn(fn) {
  depend.addDepend(fn)
}

const obj = {
  name: 'Fhup',
  age: 18
}

watchFn(function obj1Fn(){
  console.log(obj.name);
})

watchFn(function obj2Fn(){
  const newName = obj.name
  console.log(newName);
})


obj.name = 123

depend.notify()

自动监听对象变化

class Depend {
  constructor() {
    this.reactiveFns = []
  }
  addDepend(fn) {
    this.reactiveFns.push(fn)
  }
  notify() {
    this.reactiveFns.forEach(fn => {
      fn()
    })
  }
}

const depend = new Depend()
function watchFn(fn) {
  depend.addDepend(fn)
}

const obj = {
  name: 'Fhup',
  age: 18
}

// 通过Proxy()来捕获对象的属性变化.
const objProxy = new Proxy(obj, {
  get(target, key, receiver) {
    return Reflect.get(target, key, receiver)
  },
  set(target, key, newValue, receiver) {
    depend.notify()
    Reflect.set(target, key, newValue, receiver)
  }
})

watchFn(function(){
  console.log(objProxy.name);
})

watchFn(function(){
  const newName = objProxy.name
  console.log(newName);
})


objProxy.name = 'xxx'
objProxy.name = 'xxx'
objProxy.name = 'xxx'

依赖收集的管理

class Depend {
  constructor() {
    this.reactiveFns = []
  }
  addDepend(fn) {
    this.reactiveFns.push(fn)
  }
  notify() {
    this.reactiveFns.forEach(fn => {
      fn()
    })
  }
}

const depend = new Depend()
function watchFn(fn) {
  depend.addDepend(fn)
}

//封装获取Depend函数
const targetMap = new WeakMap()
function getDepend(target, key) {
  // 根据target对象获取map
  let map = targetMap.get(target)
  if(!map) {
    map = new Map()
    targetMap.set(target, map)
  }

  // 根据key获取depend对象
  let depend = map.get(key)
  if(!depend) {
    depend = new Depend()
    map.set(key, depend)
  }
  return depend
} 


const obj = {
  name: 'Fhup',
  age: 18
}

// 通过Proxy()来捕获对象的属性变化.
const objProxy = new Proxy(obj, {
  get(target, key, receiver) {
    return Reflect.get(target, key, receiver)
  },
  set(target, key, newValue, receiver) {
    Reflect.set(target, key, newValue, receiver)
    const depend = getDepend(target, key)
    depend.notify()
  }
})

watchFn(function(){
  console.log(objProxy.name);
})

watchFn(function(){
  const newName = objProxy.name
  console.log(newName);
})


objProxy.name = 'xxx'
objProxy.name = 'xxx'
objProxy.name = 'xxx'

正确的收集依赖

class Depend {
  constructor() {
    this.reactiveFns = []
  }
  addDepend(fn) {
    this.reactiveFns.push(fn)
  }
  notify() {
    this.reactiveFns.forEach(fn => {
      fn()
    })
  }
}

let activeFn = null
function watchFn(fn) {
  activeFn = fn
  fn()
  activeFn = null
}

//封装获取Depend函数
const targetMap = new WeakMap()
function getDepend(target, key) {
  // 根据target对象获取map
  let map = targetMap.get(target)
  if(!map) {
    map = new Map()
    targetMap.set(target, map)
  }

  // 根据key获取depend对象
  let depend = map.get(key)
  if(!depend) {
    depend = new Depend()
    map.set(key, depend)
  }

  return depend
} 


const obj = {
  name: 'Fhup',
  age: 18
}

// 通过Proxy()来捕获对象的属性变化.
const objProxy = new Proxy(obj, {
  get(target, key, receiver) {
    const depend = getDepend(target, key)
    // 给depend对象中添加响应函数
    depend.addDepend(activeFn)
    return Reflect.get(target, key, receiver)
  },
  set(target, key, newValue, receiver) {
    Reflect.set(target, key, newValue, receiver)
    const depend = getDepend(target, key)
    depend.notify()
  }
})

watchFn(function(){
  console.log(objProxy.name, objProxy.age, '```');
})

watchFn(function(){
  const newName = objProxy.name
  console.log(newName, '------');
})

console.log('--------------------');
objProxy.age = 'xxx'

对Depend类的重构

// 当前需要收集的响应式函数
let activeFn = null

/**
 * Depend优化:
 * 1> depend()方法
 * 2> 使用Set()保存函数, 而不是数组
 */
class Depend {
  constructor() {
    // 防止存入多个相同的变量,用 Set()
    this.reactiveFns = new Set()
  }

  depend() {
    if(activeFn) {
      this.reactiveFns.add(activeFn)
    }
  }

  notify() {
    this.reactiveFns.forEach(fn => {
      fn()
    })
  }
}


function watchFn(fn) {
  activeFn = fn
  fn()
  activeFn = null
}

//封装获取Depend函数
const targetMap = new WeakMap()
function getDepend(target, key) {
  // 根据target对象获取map
  let map = targetMap.get(target)
  if(!map) {
    map = new Map()
    targetMap.set(target, map)
  }

  // 根据key获取depend对象
  let depend = map.get(key)
  if(!depend) {
    depend = new Depend()
    map.set(key, depend)
  }

  return depend
} 


const obj = {
  name: 'Fhup',
  age: 18
}

// 通过Proxy()来捕获对象的属性变化.
const objProxy = new Proxy(obj, {
  get(target, key, receiver) {
    const depend = getDepend(target, key)
    // 给depend对象中添加响应函数
    depend.depend()
    return Reflect.get(target, key, receiver)
  },
  set(target, key, newValue, receiver) {
    Reflect.set(target, key, newValue, receiver)
    const depend = getDepend(target, key)
    depend.notify()
  }
})

watchFn(function(){
  console.log(objProxy.age, '```');
  console.log(objProxy.age, '```');
  console.log(objProxy.age, '```');
})

console.log('--------------------');
objProxy.age = 3

对象的响应式操作Vue3

// 当前需要收集的响应式函数
let activeFn = null

/**
 * Depend优化:
 * 1> depend()方法
 * 2> 使用Set()保存函数, 而不是数组
 */
class Depend {
  constructor() {
    // 防止存入多个相同的变量,用 Set()
    this.reactiveFns = new Set()
  }
  depend() {
    if(activeFn) {
      this.reactiveFns.add(activeFn)
    }
  }
  notify() {
    this.reactiveFns.forEach(fn => {
      fn()
    })
  }
}


function watchFn(fn) {
  activeFn = fn
  fn()
  activeFn = null
}

//封装获取Depend函数
const targetMap = new WeakMap()
function getDepend(target, key) {
  // 根据target对象获取map
  let map = targetMap.get(target)
  if(!map) {
    map = new Map()
    targetMap.set(target, map)
  }

  // 根据key获取depend对象
  let depend = map.get(key)
  if(!depend) {
    depend = new Depend()
    map.set(key, depend)
  }

  return depend
}

function reactive(obj) {
  // 通过Proxy()来捕获对象的属性变化.
  return new Proxy(obj, {
    get(target, key, receiver) {
      const depend = getDepend(target, key)
      // 给depend对象中添加响应函数
      depend.depend()
      return Reflect.get(target, key, receiver)
    },
    set(target, key, newValue, receiver) {
      Reflect.set(target, key, newValue, receiver)
      const depend = getDepend(target, key)
      depend.notify()
    }
  })
}

const obj = {
  name: 'Fhup',
  age: 18
}

const info = {
  address: '宝鸡市',
  height: 1.88
}

const infoProxy = reactive(info)
const objProxy = reactive(obj)

watchFn(() => {
  console.log(infoProxy.address, '~~~~~~~');
})

watchFn(() => {
  console.log(objProxy.name, '`````````');
})

infoProxy.address = '北京市'
objProxy.name = 'xxx'

对象的响应式操作Vue2

// 当前需要收集的响应式函数
let activeFn = null

/**
 * Depend优化:
 * 1> depend()方法
 * 2> 使用Set()保存函数, 而不是数组
 */
class Depend {
  constructor() {
    // 防止存入多个相同的变量,用 Set()
    this.reactiveFns = new Set()
  }
  depend() {
    if(activeFn) {
      this.reactiveFns.add(activeFn)
    }
  }
  notify() {
    this.reactiveFns.forEach(fn => {
      fn()
    })
  }
}


function watchFn(fn) {
  activeFn = fn
  fn()
  activeFn = null
}

//封装获取Depend函数
const targetMap = new WeakMap()
function getDepend(target, key) {
  // 根据target对象获取map
  let map = targetMap.get(target)
  if(!map) {
    map = new Map()
    targetMap.set(target, map)
  }

  // 根据key获取depend对象
  let depend = map.get(key)
  if(!depend) {
    depend = new Depend()
    map.set(key, depend)
  }

  return depend
}

function reactive(obj) {
  Object.keys(obj).forEach(key => {
    let value = obj[key]
    Object.defineProperty(obj, key, {
      get() {
        const depend = getDepend(obj, key)
        depend.depend()
        return value
      },
      set(newValue) {
        value = newValue
        const depend = getDepend(obj, key)
        depend.notify()
      }
    })
  })
  return obj
}

const obj = {
  name: 'Fhup',
  age: 18
}

const info = {
  address: '宝鸡市',
  height: 1.88
}

const infoProxy = reactive(info)
const objProxy = reactive(obj)

watchFn(() => {
  console.log(infoProxy.address, '~~~~~~~');
})

watchFn(() => {
  console.log(objProxy.name, '`````````');
})

infoProxy.address = '北京市'
objProxy.name = 'xxx'