响应式原理
2022-10-08 本文已影响0人
未路过
1 什么是响应式
2 响应式函数设计
// 封装一个响应式的函数
let reactiveFns = []
function watchFn(fn) {
reactiveFns.push(fn)
}
// 对象的响应式
const obj = {
name: "why",
age: 18
}
watchFn(function() {
const newName = obj.name
console.log("你好啊, 李银河")
console.log("Hello World")
console.log(obj.name) // 100行
})
watchFn(function() {
console.log(obj.name, "demo function -------")
})
function bar() {
console.log("普通的其他函数")
console.log("这个函数不需要有任何响应式")
}
obj.name = "kobe"
reactiveFns.forEach(fn => {
fn()
})
3 依赖收集类的封装
class Depend {
constructor() {
this.reactiveFns = []
}
addDepend(reactiveFn) {
this.reactiveFns.push(reactiveFn)
}
notify() {
this.reactiveFns.forEach(fn => {
fn()
})
}
}
// 封装一个响应式的函数
const depend = new Depend()
function watchFn(fn) {
depend.addDepend(fn)
}
// 对象的响应式
const obj = {
name: "why", // depend对象
age: 18 // depend对象
}
watchFn(function() {
const newName = obj.name
console.log("你好啊, 李银河")
console.log("Hello World")
console.log(obj.name) // 100行
})
watchFn(function() {
console.log(obj.name, "demo function -------")
})
obj.name = "kobe"
depend.notify()
4 自动监听对象变化
那么我们接下来就可以通过之前学习的方式来监听对象的变量:
方式一:通过 Object.defineProperty的方式(vue2采用的方式);
方式二:通过new Proxy的方式(vue3采用的方式);
class Depend {
constructor() {
this.reactiveFns = []
}
addDepend(reactiveFn) {
this.reactiveFns.push(reactiveFn)
}
notify() {
this.reactiveFns.forEach(fn => {
fn()
})
}
}
// 封装一个响应式的函数
const depend = new Depend()
function watchFn(fn) {
depend.addDepend(fn)
}
// 对象的响应式
const obj = {
name: "why", // depend对象
age: 18 // depend对象
}
// 监听对象的属性变量: Proxy(vue3)/Object.defineProperty(vue2)
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.notify()
}
})
watchFn(function() {
const newName = objProxy.name
console.log("你好啊, 李银河")
console.log("Hello World")
console.log(objProxy.name) // 100行
})
watchFn(function() {
console.log(objProxy.name, "demo function -------")
})
watchFn(function() {
console.log(objProxy.age, "age 发生变化是需要执行的----1")
})
watchFn(function() {
console.log(objProxy.age, "age 发生变化是需要执行的----2")
})
objProxy.name = "kobe"
objProxy.name = "james"
objProxy.name = "curry"
objProxy.age = 100
5 依赖收集的管理
class Depend {
constructor() {
this.reactiveFns = []
}
addDepend(reactiveFn) {
this.reactiveFns.push(reactiveFn)
}
notify() {
this.reactiveFns.forEach(fn => {
fn()
})
}
}
// 对象的响应式
const obj1 = {
name: "why", // depend对象
age: 18 // depend对象
};
const obj2 = {
name: "kobe", // depend对象
age: 32 // depend对象
};
const weakMap = new WeakMap();
const objtest = { name: 'key' }
// console.log(weakMap.set(objtest, 'aaa'))
console.log(weakMap.get(objtest)) //undefined 没有的化返回的是undefined
function setDepend(target, key) {
let targetMap = weakMap.get(target);
if (!targetMap) {
targetMap = new Map();
weakMap.set(target, targetMap);
}
let depend = targetMap.get(key);
if (!depend) {
depend = new Depend();
targetMap.set(key, depend)
}
return depend
}
/* const objProxy = new Proxy(obj1, {
get: function (target, key, receiver) {
return Reflect.get(target, key, receiver)
},
set: function (target, key, newVaule, receiver) {
Reflect.set(target, key, newVaule, receiver);
setDepend(target, key).notify();
}
}) */
//forEach没有返回值,map有
let [obj1Proxy, obj2Proxy] = [obj1, obj2].map(item => {
return new Proxy(item, {
get: function (target, key, receiver) {
return Reflect.get(target, key, receiver)
},
set: function (target, key, newVaule, receiver) {
Reflect.set(target, key, newVaule, receiver);
setDepend(target, key).notify();
}
})
});
function obj1NameFn1() {
console.log(obj1Proxy.name);
console.log("obj1NameFn1被执行")
}
function obj1NameFn2() {
console.log("obj1NameFn2被执行")
}
function obj1AgeFn1() {
console.log("obj1AgeFn1被执行")
}
function obj1AgeFn2() {
console.log("obj1AgeFn2被执行")
}
function obj2NameFn1() {
console.log("obj2NameFn1被执行")
}
function obj2NameFn2() {
console.log("obj2NameFn2被执行")
}
function obj2AgeFn1() {
console.log("obj2AgeFn1")
}
function obj2AgeFn2() {
console.log("obj2AgeFn2")
}
/* WeakMap应用里面的方法
const obj1PropertyMap = new Map()
obj1PropertyMap.set('name', [obj1NameFn1, obj1NameFn2])
obj1PropertyMap.set('age', [obj1AgeFn1, obj1AgeFn2])
const obj2PropertyMap = new Map()
obj2PropertyMap.set('name', [obj2NameFn1, obj2NameFn2])
obj2PropertyMap.set('age', [obj2AgeFn1, obj2AgeFn2])
const objWeakMap = new WeakMap()
objWeakMap.set(obj1, obj1PropertyMap)
objWeakMap.set(obj2, obj2PropertyMap)
objWeakMap
.get(obj1)
.get('name')
.forEach((fn) => fn()) */
function watchFn(target, key, ...fns) {
fns.forEach(item => {
setDepend(target, key).addDepend(item);
})
}
watchFn(obj1, "name", obj1NameFn1, obj1NameFn2);
watchFn(obj1, "age", obj1AgeFn1, obj1AgeFn2 )
watchFn(obj2, "name", obj2NameFn1, obj2NameFn2);
watchFn(obj2, "age", obj2AgeFn1, obj2AgeFn2 )
obj1Proxy.name = "coder";
obj1Proxy.age = 118;
obj2Proxy.name = "jiff";
obj2Proxy.age = 89;
console.log(obj2Proxy.age);
6 正确的收集依赖
上面时通过watchFn(obj1, "name", obj1NameFn1, obj1NameFn2);这个方法,手动的为obj1的name属性添加了方法obj1NameFn1和obj1NameFn2, 我们想着就是不手动添加这个,就是自动的往weakMap的obj1的map的“name”里面添加方法。函数里面有obj1Proxy.name的就放到obj1->name的数组中去。有obj1Proxy.age的就放到obj1->age的数组(this.reactiveFns)中去.
class Depend {
constructor() {
this.reactiveFns = []
}
addDepend(reactiveFn) {
this.reactiveFns.push(reactiveFn)
}
notify() {
this.reactiveFns.forEach(fn => {
fn()
})
}
}
// 对象的响应式
const obj1 = {
name: "why", // depend对象
age: 18 // depend对象
};
const obj2 = {
name: "kobe", // depend对象
age: 32 // depend对象
};
const weakMap = new WeakMap();
function setDepend(target, key) {
let targetMap = weakMap.get(target);
if (!targetMap) {
targetMap = new Map();
weakMap.set(target, targetMap);
}
let depend = targetMap.get(key);
if (!depend) {
depend = new Depend();
targetMap.set(key, depend)
}
return depend
}
/* const objProxy = new Proxy(obj1, {
get: function (target, key, receiver) {
return Reflect.get(target, key, receiver)
},
set: function (target, key, newVaule, receiver) {
Reflect.set(target, key, newVaule, receiver);
setDepend(target, key).notify();
}
}) */
//forEach没有返回值,map有
let [obj1Proxy, obj2Proxy] = [obj1, obj2].map(item => {
return new Proxy(item, {
get: function (target, key, receiver) {
if(activeReactiveFn){
console.log('watchFn内的调用');
setDepend(target, key).addDepend(activeReactiveFn);
}
return Reflect.get(target, key, receiver)
},
set: function (target, key, newVaule, receiver) {
Reflect.set(target, key, newVaule, receiver);
setDepend(target, key).notify();
}
})
});
function obj1NameFn1() {
console.log(obj1Proxy.name + " obj1NameFn1被执行 ")
console.log(obj2Proxy.name + " obj1NameFn1被执行 ")
}
function obj1NameFn2() {
console.log(obj1Proxy.name + " obj1NameFn2被执行 ")
}
function obj1AgeFn1() {
console.log(obj1Proxy.age + " obj1AgeFn1被执行 ")
}
function obj1AgeFn2() {
console.log(obj1Proxy.age + " obj1AgeFn2被执行 ")
}
function obj2NameFn1() {
console.log(obj2Proxy.name + " obj2NameFn1被执行 ")
}
function obj2NameFn2() {
console.log(obj2Proxy.name + " obj2NameFn2被执行 ")
}
function obj2AgeFn1() {
console.log(obj2Proxy.age + " obj2AgeFn1被执行 ")
}
function obj2AgeFn2() {
console.log(obj2Proxy.age + " obj2AgeFn2被执行 ")
}
let activeReactiveFn = null;
function watchFn(fn) {
activeReactiveFn = fn;
fn();
activeReactiveFn = null;
}
/*
给各个函数分配到obj1/obj2的map里面
*/
watchFn(obj1NameFn1);
watchFn(obj1NameFn2);
watchFn(obj1AgeFn1);
watchFn(obj1AgeFn2);
watchFn(obj2NameFn1);
watchFn(obj2NameFn2);
watchFn(obj2AgeFn1);
watchFn(obj2AgeFn2);
console.log('-----------------------------------------');
console.log(obj1Proxy.name);
obj1Proxy.name = "coder";
obj2Proxy.name = "test";
/*
obj1Proxy.age = 118;
obj2Proxy.age = 89;
console.log(obj2Proxy.age); */
14.7 对Depend类重构
我们不想让get里面知道有activeReactiveFn这个东西
get: function (target, key, receiver) {
if(activeReactiveFn){
console.log('watchFn内的调用');
setDepend(target, key).addDepend(activeReactiveFn);
}
// 保存当前需要收集的响应式函数
let activeReactiveFn = null
/**
* Depend优化:
* 1> depend方法
* 2> 使用Set来保存依赖函数, 而不是数组[]
*/
class Depend {
constructor() {
this.reactiveFns = new Set()
}
/* addDepend(reactiveFn) {
this.reactiveFns.add(reactiveFn)
} */
depend() {
if(activeReactiveFn){
// console.log('watchFn内的调用');
this.reactiveFns.add(activeReactiveFn)
}
}
notify() {
this.reactiveFns.forEach(fn => {
fn()
})
}
}
// 对象的响应式
const obj1 = {
name: "why", // depend对象
age: 18 // depend对象
};
const obj2 = {
name: "kobe", // depend对象
age: 32 // depend对象
};
const weakMap = new WeakMap();
function setDepend(target, key) {
let targetMap = weakMap.get(target);
if (!targetMap) {
targetMap = new Map();
weakMap.set(target, targetMap);
}
let depend = targetMap.get(key);
if (!depend) {
depend = new Depend();
targetMap.set(key, depend)
}
return depend
}
/* const objProxy = new Proxy(obj1, {
get: function (target, key, receiver) {
return Reflect.get(target, key, receiver)
},
set: function (target, key, newVaule, receiver) {
Reflect.set(target, key, newVaule, receiver);
setDepend(target, key).notify();
}
}) */
//forEach没有返回值,map有
let [obj1Proxy, obj2Proxy] = [obj1, obj2].map(item => {
return new Proxy(item, {
get: function (target, key, receiver) {
setDepend(target, key).depend();
return Reflect.get(target, key, receiver)
},
set: function (target, key, newVaule, receiver) {
Reflect.set(target, key, newVaule, receiver);
setDepend(target, key).notify();
}
})
});
function watchFn(fn) {
activeReactiveFn = fn;
fn();
activeReactiveFn = null;
}
// watchFn
watchFn(() => {
console.log(obj1Proxy.name, "-------")
console.log(obj1Proxy.name, "+++++++")
})
//如果不用set的话,一个函数会被往数组里面加2次。如果一个函数里面有三个obj1Proxy.name,则会被加3次,一次类推
obj1Proxy.name = "kobe";
obj2Proxy.name = "test";
/*
test.html:150 why -------
test.html:151 why +++++++
test.html:150 kobe -------
test.html:151 kobe +++++++
*/
14.8 对象的响应式操作vue3
把一个对象封装成响应式的
我们目前的响应式是针对于obj一个对象的,我们可以创建出来一个函数,针对所有的对象都可以变成响应式对象:
// 保存当前需要收集的响应式函数
let activeReactiveFn = null
/**
* Depend优化:
* 1> depend方法
* 2> 使用Set来保存依赖函数, 而不是数组[]
*/
class Depend {
constructor() {
this.reactiveFns = new Set()
}
depend() {
if(activeReactiveFn){
// console.log('watchFn内的调用');
this.reactiveFns.add(activeReactiveFn)
}
}
notify() {
this.reactiveFns.forEach(fn => {
fn()
})
}
}
const weakMap = new WeakMap();
function setDepend(target, key) {
let targetMap = weakMap.get(target);
if (!targetMap) {
targetMap = new Map();
weakMap.set(target, targetMap);
}
let depend = targetMap.get(key);
if (!depend) {
depend = new Depend();
targetMap.set(key, depend)
}
return depend
}
function reactive(obj) {
return new Proxy(obj, {
get: function (target, key, receiver) {
setDepend(target, key).depend();
return Reflect.get(target, key, receiver)
},
set: function (target, key, newVaule, receiver) {
Reflect.set(target, key, newVaule, receiver);
setDepend(target, key).notify();
}
})
}
function watchFn(fn) {
activeReactiveFn = fn;
fn();
activeReactiveFn = null;
}
// 对象的响应式
const obj1 = {
name: "why", // depend对象
age: 18 // depend对象
};
const obj2 = {
name: "kobe", // depend对象
age: 32 // depend对象
};
const obj1Proxy = reactive(obj1);
const obj2Proxy = reactive(obj2);
const obj3Proxy = reactive({
address: "广州市",
height: 1.88
})
// watchFn
watchFn(() => {
console.log(obj1Proxy.name, "-------")
console.log(obj1Proxy.name, "+++++++")
})
obj1Proxy.name = "coderwhy"
watchFn(() => {
console.log(obj3Proxy.address)
})
obj3Proxy.address = "北京市";
obj2Proxy.name = "test";
console.log(obj2Proxy.name );
14.9 对象的响应式操作vue2
使用object.definProperty
// 保存当前需要收集的响应式函数
let activeReactiveFn = null
/**
* Depend优化:
* 1> depend方法
* 2> 使用Set来保存依赖函数, 而不是数组[]
*/
class Depend {
constructor() {
this.reactiveFns = new Set()
}
depend() {
if(activeReactiveFn){
// console.log('watchFn内的调用');
this.reactiveFns.add(activeReactiveFn)
}
}
notify() {
this.reactiveFns.forEach(fn => {
fn()
})
}
}
const weakMap = new WeakMap();
function setDepend(target, key) {
let targetMap = weakMap.get(target);
if (!targetMap) {
targetMap = new Map();
weakMap.set(target, targetMap);
}
let depend = targetMap.get(key);
if (!depend) {
depend = new Depend();
targetMap.set(key, depend)
}
return depend
}
function reactive(obj) {
Object.keys(obj).forEach(item => {
console.log(item);
let value = obj[item];
Object.defineProperty(obj, item, {
get(){
setDepend(obj, item).depend();
return value
},
set(newValue){
value = newValue;
setDepend(obj, item).notify();
}
})
})
return obj
}
function watchFn(fn) {
activeReactiveFn = fn;
fn();
activeReactiveFn = null;
}
// 对象的响应式
const obj1 = {
name: "why", // depend对象
age: 18 // depend对象
};
const obj2 = {
name: "kobe", // depend对象
age: 32 // depend对象
};
const obj1Proxy = reactive(obj1);
const obj2Proxy = reactive(obj2);
const obj3Proxy = reactive({
address: "广州市",
height: 1.88
})
// watchFn
watchFn(() => {
console.log(obj1Proxy.name, "-------")
console.log(obj1Proxy.name, "+++++++")
})
obj1Proxy.name = "coderwhy"
watchFn(() => {
console.log(obj3Proxy.address)
})
obj3Proxy.address = "北京市";
obj2Proxy.name = "test";
console.log(obj2Proxy.name );