初步进行响应式函数封装
思路如下:当对象的属性进行改变时,手动通知需要执行的函数
let reactiveFns = []
function watchFn(fn) {
reactiveFns.push(fn)
}
const obj = {
name: "lhm",
age: 18
}
function foo() {
console.log('这是需要执行的代码');
}
watchFn(foo)
function bar() {
console.log("这个函数不需要接收");
}
obj.name = 'kobe'
reactiveFns.forEach(fn => {
fn()
})
第二步:依赖收集类的封装
思路如下:使用Depend类收集某个属性的所有依赖,每个属性都会对应一个类的对象,每个对象都会有一个reactiveFns数组,数组里存储每一个需要执行的函数,notyfy函数用来通知该执行的函数
class Depend {
constructor () {
this.reactiveFns = []
}
addDepend(reactiveFn) {
this.reactiveFns.push(reactiveFn)
}
notyfy() {
this.reactiveFns.forEach(fn => {
fn()
})
}
}
const depend = new Depend()
function watchFn(fn) {
depend.addDepend(fn)
}
const obj = {
name: "lhm",
age: 18
}
watchFn(function () {
console.log(objProxy.name + '发生变化需要执行的代码');
})
watchFn(function () {
console.log(objProxy.age + '发生变化需要执行的代码');
})
obj.name = 'kobe'
depend.notyfy()
第三步:自动监听属性的变化,然后执行depend的notify函数
思路如下:监听对象的属性变化有常用的两种方式:Proxy(Vue3的实现原理)和defineProepet(Vue2的实现原理),以下使用Proxy
class Depend {
constructor () {
this.reactiveFns = []
}
addDepend(reactiveFn) {
this.reactiveFns.push(reactiveFn)
}
notyfy() {
this.reactiveFns.forEach(fn => {
fn()
})
}
}
const depend = new Depend()
function watchFn(fn) {
depend.addDepend(fn)
}
const obj = {
name: "lhm",
age: 18
}
const objProxy = new Proxy(obj, {
get: function (target, key, receiver) {
return Reflect.get(target, key, receiver)
},
set: function (target, key, newValue, receiver) {
Reflect.set(target, key, newValue, receiver)
depend.notyfy()
}
})
watchFn(function () {
console.log(objProxy.name + '发生变化需要执行的代码');
})
watchFn(function () {
console.log(objProxy.age + '发生变化需要执行的代码');
})
objProxy.name = 'kobe'
objProxy.age = 30
第四步:依赖收集的管理
思路如下:在代理对象的get上收集函数,并把函数存入对应的depend对象中
class Depend {
constructor () {
this.reactiveFns = []
}
addDepend(reactiveFn) {
this.reactiveFns.push(reactiveFn)
}
notyfy() {
this.reactiveFns.forEach(fn => {
fn()
})
}
}
let activeReactiveFn = null
function watchFn(fn) {
activeReactiveFn = fn
fn()
}
const targetMap = new WeakMap()
function getDepend(target, key) {
let map = targetMap.get(target)
if(!map) {
map = new Map()
targetMap.set(target, map)
}
let depend = map.get(key)
if(!depend) {
depend = new Depend()
map.set(key, depend)
}
return depend
}
const obj = {
name: "lhm",
age: 18
}
const info = {
address: '广州市'
}
const objProxy = new Proxy(obj, {
get: function (target, key, receiver) {
const depend = getDepend(target, key)
depend.addDepend(activeReactiveFn)
return Reflect.get(target, key, receiver)
},
set: function (target, key, newValue, receiver) {
Reflect.set(target, key, newValue, receiver)
const depend = getDepend(target, key)
depend.notyfy()
}
})
watchFn(function () {
console.log(objProxy.name + '发生变化需要执行的代码1');
})
watchFn(function () {
console.log(objProxy.age + '发生变化需要执行的代码1');
})
watchFn(function () {
console.log(objProxy.age + '新函数');
})
objProxy.age = 30
objProxy.name = '啦啦啦'
第五步:对depend类的优化和重构
(1) depend方法
(2) 使用Set来保存依赖函数而不是数组[]
let activeReactiveFn = null
class Depend {
constructor () {
this.reactiveFns = new Set()
}
addDepend(reactiveFn) {
this.reactiveFns.add(reactiveFn)
}
depend() {
if(activeReactiveFn) {
this.reactiveFns.add(activeReactiveFn)
}
}
notyfy() {
this.reactiveFns.forEach(fn => {
fn()
})
}
}
function watchFn(fn) {
activeReactiveFn = fn
fn()
}
const targetMap = new WeakMap()
function getDepend(target, key) {
let map = targetMap.get(target)
if(!map) {
map = new Map()
targetMap.set(target, map)
}
let depend = map.get(key)
if(!depend) {
depend = new Depend()
map.set(key, depend)
}
return depend
}
const obj = {
name: "lhm",
age: 18
}
const info = {
address: '广州市'
}
const objInfo = recative(info)
const objObj = recative(obj)
function recative(obj) {
return new Proxy(obj, {
get: function (target, key, receiver) {
const depend = getDepend(target, key)
depend.depend()
return Reflect.get(target, key, receiver)
},
set: function (target, key, newValue, receiver) {
Reflect.set(target, key, newValue, receiver)
const depend = getDepend(target, key)
depend.notyfy()
}
})
}
watchFn(function () {
console.log(objProxy.name + '----------------');
console.log(objProxy.name + '++++++++++++++++');
})
objProxy.name = '啦啦啦'
vue2的响应式原理
let activeReactiveFn = null
class Depend {
constructor () {
this.reactiveFns = new Set()
}
addDepend(reactiveFn) {
this.reactiveFns.add(reactiveFn)
}
depend() {
if(activeReactiveFn) {
this.reactiveFns.add(activeReactiveFn)
}
}
notyfy() {
this.reactiveFns.forEach(fn => {
fn()
})
}
}
function watchFn(fn) {
activeReactiveFn = fn
fn()
}
const targetMap = new WeakMap()
function getDepend(target, key) {
let map = targetMap.get(target)
if(!map) {
map = new Map()
targetMap.set(target, map)
}
let depend = map.get(key)
if(!depend) {
depend = new Depend()
map.set(key, depend)
}
return depend
}
const obj = {
name: "lhm",
age: 18
}
const info = {
address: '广州市'
}
const objInfo = recative(info)
const objObj = recative(obj)
function recative(obj) {
obj.keys.forEach(key => {
let value = obj[key]
Object.defineProperty(obj, key, {
get: function() {
const depend = getDepend(obj, key)
depend.depend()
return value
},
set: function (newVallue) {
const depend = getDepend(obj, key)
depend.notyfy()
obj[key] = newVallue
}
})
})
return obj
}
watchFn(function () {
console.log(objProxy.name + '----------------');
console.log(objProxy.name + '++++++++++++++++');
})
objProxy.name = '啦啦啦'
总结:以weakMap => Map => depend对象的数据结构来保存每一个函数和对象的关系,在对象获取时进行收集,对象赋值时通知每一个函数执行