总结:
1. 什么是响应式
2. 响应式函数的封装
3. Depend 类的封装
4. 监听对象的变化
a. new Proxy(, set: depend.notify)
5. 依赖收集的数据结构 weakMap
6. 正确的收集依赖
a. Proxy 的get方法中收集对应的函数
b. 在全局activeReactiveFn变量
c. 在get中找到depend对象,addDepend(全局activeReactiveFn变量)
7. 对Depend进行优化
a. addDepend函数换成depend函数
b. 将保存的数组换成set
8. 对对象的响应式 *** 作
a. new Proxy() vue3
b. Object.defineProperty() vue2
一、Proxy
1、监听对象的 *** 作 - Object.defineProperty()
通过使用Object.defineProperty()
const obj = {
name: "chen",
age: 23,
};
// 1.监听一个属性
// Object.defineProperty(obj, "name", {
// get: function () {
// console.log("监听到name被访问");
// return this;
// },
// set: function () {
// console.log("监听到被设置");
// },
// });
// console.log(obj.name);
// obj.name = '天选之子'
// 2.监听两个属性
Object.keys(obj).forEach((item) => {
console.log(item);
Object.defineProperty(obj, item, {
get() {
console.log("get监听");
},
set(value) {
obj['item'] = value;
console.log("set设置");
},
});
});
obj.name = "kobe";
obj.age = 23;
console.log(obj);
2、监听对象的 *** 作2 - 引出 Proxy弊端:
const obj = {
name: "chen",
age: 23,
};
// 参数: 对象, 捕获器对象
const objProxy = new Proxy(obj, {
// 1、获取值时的捕获器, 会替换调原来获取值的,自动回调get
// target:就是被代理的对象 key:obj中的key
get(target, key) {
return target[key];
},
// 2、设置值时的捕获器
set(target, key, value) {
target[key] = value;
},
// 3、监听in捕获器
has(target, key){
console.log('监听in *** 作');
return key in target;
},
// 4、监听delete *** 作
delete(target, key){
console.log('监听删除 *** 作');
delete target[key];
}
});
objProxy.name = "陈胜";
console.log(objProxy.age); //23
console.log(objProxy.name); //chen
// 发现原来的obj对象也被改掉了
console.log(obj.age); //23
console.log(obj.name); //chen
// in *** 作符
console.log("name" in objProxy);//true
// delete *** 作
delete objProxy.name;
console.log(obj);
3、Proxy对函数对象的监听
function foo() {}
const fooProxy = new Proxy(foo, {
apply: function (target, thisArg, argArray) {
console.log("对apply进行调用");
return target.apply(thisArg, argArray);
},
construct: function (target, argArray) {
console.log("对new进行调用");
return new target(...argArray);
},
});
foo();
fooProxy.apply({}, ["abc", "cde"]); // apply进行调用
new fooProxy("abc", "cdd"); // new进行调用
二、Reflect
1、Reflect 引入
刚好跟Proxy中的13个方法一一对应
const obj = {
name: "chen",
age: 23,
};
const objProxy = new Proxy(obj, {
get(target, key) {
// return target[key];
return Reflect.get(target, key);
},
set(target, key, value) {
// target[key] = value;
// 其实Reflect设置值会返回一个布尔值的
Reflect.set(target, key, value);
},
});
objProxy.name = "陈胜";
console.log(objProxy.age); //23
console.log(objProxy.name); // 陈胜
console.log(obj.age); //23
console.log(obj.name); //陈胜
2、Reflect 的作用
const obj = {
_name: "chen",
get name() {
return this._name; //不好确定this,
},
set name(value) {
this._name = value;
},
};
const objProxy = new Proxy(obj, {
get(target, key, receiver) {
// receiver是创建出来的代理对象objProxy,
console.log("get方法被访问---", key, receiver);
console.log(receiver === objProxy);
// Reflect第三个参数,如果传了,那么就会被传递到的obj调用get name()方法对象里面
return Reflect.get(target, key, receiver);
},
set(target, key, value, receiver) {
console.log("set方法被访问---", key, receiver);
Reflect.set(target, key, value, receiver);
},
});
console.log(objProxy.name);
objProxy.name = "天选之子";
// 注:set、get都会别访问两次
3、Reflect中的construct作用
function Student(name, age) {
// 我们之前是调用super(name, age)
this.name = name;
this.age = age;
}
function Teacher() {}
// 执行student里面的内容,创建出来的对象是Teacher类型
const teacher = Reflect.construct(Student, ["chen", 23], Teacher);
console.log(teacher); //Teacher { name: 'chen', age: 23 }
console.log(teacher.__proto__ === Teacher.prototype); //true
三、响应式原理
1、响应式函数的封装
// 封装一个响应式函数
// name发生改变的所有需要重新执行的函数, 数组不是很方便,如果里面有age呢, 我们该用类
let reactiveFns = [];
function watchFn(fn) {
reactiveFns.push(fn);
}
// 对象的响应式
const obj = {
name: "chen",
age: 23,
};
watchFn(function () {
const newName = obj.name;
console.log("你好");
console.log(obj.name);
});
watchFn(function () {
console.log(obj.name, "demo function----");
});
obj.name = "天线大爷";
reactiveFns.forEach((fn) => {
fn();
});
2、依赖收集类的封装
class Depend {
constructor() {
this.reactiveFns = [];
}
// 让每个属性对应一个Depend类
addDepend(reactiveFn) {
this.reactiveFns.push(reactiveFn);
}
notify() {
this.reactiveFns.forEach((fn) => fn());
}
}
// 封装一个响应式函数
// name发生改变的所有需要重新执行的函数, 数组不是很方便,如果里面有age呢, 我们该用类
// let reactiveFns = [];
const depend = new Depend();
function watchFn(fn) {
// reactiveFns.push(fn);
depend.addDepend(fn);
}
// 对象的响应式
const obj = {
name: "chen",
age: 23,
};
watchFn(function () {
const newName = obj.name;
console.log("你好");
console.log(obj.name);
});
watchFn(function () {
console.log(obj.name, "demo function----");
});
obj.name = "天线大爷";
depend.notify();
// reactiveFns.forEach((fn) => {
// fn();
// });
3、自动监听对象变化
class Depend {
constructor() {
this.reactiveFns = [];
}
// 让每个属性对应一个Depend类
addDepend(reactiveFn) {
this.reactiveFns.push(reactiveFn);
}
notify() {
this.reactiveFns.forEach((fn) => fn());
}
}
// 封装一个响应式函数
// name发生改变的所有需要重新执行的函数, 数组不是很方便,如果里面有age呢, 我们该用类
// let reactiveFns = [];
const depend = new Depend();
function watchFn(fn) {
// reactiveFns.push(fn);
depend.addDepend(fn);
}
// 对象的响应式
const obj = {
name: "chen",
age: 23,
};
// 监听对象的属性变化:
// 两种方式: 1、Proxy(vue3实现原理) 2、Object.defineProperty(value, property, receiver)
const objProxy = new Proxy(obj, {
get(target, key, receiver) {
return Reflect.get(target, key, receiver);
},
set(target, key, value, receiver) {
Reflect.set(target, key, value, receiver);
// 改变属性自动执行notify
depend.notify();
},
});
watchFn(function () {
const newName = objProxy.name;
console.log("你好");
console.log(objProxy.name);
});
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 = "天线大爷";
objProxy.name = "天线大爷2";
objProxy.name = "天线大爷3";
objProxy.age = 200;
// 不应该手动,应该监听对象属性变化
// 所以有回到了 监听对象的属性变化: 两种方式: 1、Proxy(vue3实现原理)、2、Object.defineProperty(value, property, receiver)
// depend.notify();
// reactiveFns.forEach((fn) => {
// fn();
// });
4、依赖收集的管理
// 每个属性对应一个Depend对象
class Depend {
constructor() {
this.reactiveFns = [];
}
// 让每个属性对应一个Depend类
addDepend(reactiveFn) {
this.reactiveFns.push(reactiveFn);
}
notify() {
this.reactiveFns.forEach((fn) => fn());
}
}
// 封装一个响应式函数
// name发生改变的所有需要重新执行的函数, 数组不是很方便,如果里面有age呢, 我们该用类
// let reactiveFns = [];
const depend = new Depend();
function watchFn(fn) {
// reactiveFns.push(fn);
depend.addDepend(fn);
}
// 封装一个获取Depend函数
const targetMap = new WeakMap();
function getDepend(target, key) {
// 1.根据target对象获取map的过程
let map = targetMap.get(target);
if (!map) {
map = new Map();
targetMap.set(target, map);
}
// 2.根据key获取depend对象
let depend = map.get(key);
if (!depend) {
depend = new Depend();
map.set(key, depend);
}
return depend;
}
// 对象的响应式
const obj = {
name: "chen",
age: 23,
};
// 监听对象的属性变化:
// 两种方式: 1、Proxy(vue3实现原理) 2、Object.defineProperty(value, property, receiver)
const objProxy = new Proxy(obj, {
get(target, key, receiver) {
return Reflect.get(target, key, receiver);
},
set(target, key, value, receiver) {
Reflect.set(target, key, value, receiver);
// 改变属性自动执行notify
// depend.notify();
const depend = getDepend(target, key);
console.log(depend.reactiveFns);
depend.notify();
},
});
watchFn(function () {
const newName = objProxy.name;
console.log("你好");
console.log(objProxy.name);
});
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 = "天线大爷";
objProxy.name = "天线大爷2";
objProxy.name = "天线大爷3";
objProxy.age = 200;
const info = {
address: "深圳",
};
watchFn(function () {
console.log(info.address, "address变化1------");
});
watchFn(function () {
console.log(info.address, "address变化2------");
});
对象的依赖管理:
class Depend {
constructor() {
this.reactiveFns = [];
}
addDepend(reactiveFn) {
this.reactiveFns.push(reactiveFn);
}
notify() {
this.reactiveFns.forEach((fn) => {
fn();
});
}
}
// const depend = new Depend();
let activeReactiveFn = null;
function watchFn(fn) {
// depend.addDepend(fn);
activeReactiveFn = fn;
fn();
activeReactiveFn = null;
}
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: "chen",
age: 23,
};
const objProxy = new Proxy(obj, {
get(target, key, receiver) {
// 根据target,key获取可以对应的depend
const depend = getDepend(target, key);
// 给depend对象添加响应函数
depend.addDepend(activeReactiveFn);
return Reflect.get(target, key, receiver);
},
set(target, key, value, receiver) {
Reflect.set(target, key, value, receiver);
const depend = getDepend(target, key);
console.log(depend.reactiveFns);
depend.notify();
},
});
watchFn(function () {
console.log('第一次执行')
console.log("你好name");
console.log(objProxy.name);
});
watchFn(function () {
console.log(objProxy.name, "name function----");
});
watchFn(function () {
console.log(objProxy.age, "age 变化1----");
});
watchFn(function () {
console.log(objProxy.age, "age 变化2----");
});
objProxy.name = "天线大爷";
// objProxy.name = "天线大爷2";
// objProxy.name = "天线大爷3";
// objProxy.age = 200;
// const info = {
// address: "深圳",
// };
// watchFn(function () {
// console.log(info.address, "address变化1------");
// });
// watchFn(function () {
// console.log(info.address, "address变化2------");
// });
6、Depend类的优化
// let activeReactiveFn: 当前需要收集的响应式函数
let activeReactiveFn = null;
/**
* Depend优化:
* 1、depeng方法
* 2、使用Set来保存依赖函数,而不是数组[]
*/
class Depend {
constructor() {
// this.reactiveFns = [];
this.reactiveFns = new Set();
}
addDepend(reactiveFn) {
this.reactiveFns.add(reactiveFn);
}
depend() {
if (activeReactiveFn) {
this.reactiveFns.add(activeReactiveFn);
}
}
notify() {
this.reactiveFns.forEach((fn) => {
fn();
});
}
}
// const depend = new Depend();
function watchFn(fn) {
// depend.addDepend(fn);
activeReactiveFn = fn;
fn();
activeReactiveFn = null;
}
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: "chen",
age: 23,
};
const objProxy = new Proxy(obj, {
get(target, key, receiver) {
const depend = getDepend(target, key);
// depend.addDepend(activeReactiveFn);
depend.depend();
return Reflect.get(target, key, receiver);
},
set(target, key, value, receiver) {
Reflect.set(target, key, value, receiver);
const depend = getDepend(target, key);
console.log(depend.reactiveFns);
depend.notify();
},
});
watchFn(() => {
// 被执行了 两次,objProxy.name收集了两次。改成set就执行一次
console.log(objProxy.name, "/==========");
console.log(objProxy.name, "+++++++++++++");
});
objProxy.name = "陈胜";
7、对象的响应式 *** 作(vue3原理)
let activeReactiveFn = null;
class Depend {
constructor() {
// this.reactiveFns = [];
this.reactiveFns = new Set();
}
addDepend(reactiveFn) {
this.reactiveFns.add(reactiveFn);
}
depend() {
if (activeReactiveFn) {
this.reactiveFns.add(activeReactiveFn);
}
}
notify() {
this.reactiveFns.forEach((fn) => {
fn();
});
}
}
function watchFn(fn) {
activeReactiveFn = fn;
fn();
activeReactiveFn = null;
}
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;
}
function reactive(obj) {
return new Proxy(obj, {
get(target, key, receiver) {
const depend = getDepend(target, key);
depend.depend();
return Reflect.get(target, key, receiver);
},
set(target, key, value, receiver) {
Reflect.set(target, key, value, receiver);
const depend = getDepend(target, key);
console.log(depend.reactiveFns);
depend.notify();
},
});
}
const obj = {
name: "chen",
age: 23,
};
const objProxy = new Proxy(obj, {
get(target, key, receiver) {
const depend = getDepend(target, key);
depend.depend();
return Reflect.get(target, key, receiver);
},
set(target, key, value, receiver) {
Reflect.set(target, key, value, receiver);
const depend = getDepend(target, key);
console.log(depend.reactiveFns);
depend.notify();
},
});
const info = {
address: "深圳",
height: 1.6,
};
const infoProxy = reactive(info);
watchFn(function () {
console.log(infoProxy.address);
});
infoProxy.address = "广州";
// 简化 *** 作
const foo = reactive({
name: "foo",
});
watchFn(function () {
console.log(foo.name + " hello");
});
foo.name = "bar";
8、对象的响应式 *** 作(vue2原理)
let activeReactiveFn = null;
class Depend {
constructor() {
// this.reactiveFns = [];
this.reactiveFns = new Set();
}
addDepend(reactiveFn) {
this.reactiveFns.add(reactiveFn);
}
depend() {
if (activeReactiveFn) {
this.reactiveFns.add(activeReactiveFn);
}
}
notify() {
this.reactiveFns.forEach((fn) => {
fn();
});
}
}
function watchFn(fn) {
activeReactiveFn = fn;
fn();
activeReactiveFn = null;
}
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;
}
function reactive(obj) {
// es6之前监听对象属性
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: "chen",
age: 23,
};
const objProxy = new Proxy(obj, {
get(target, key, receiver) {
const depend = getDepend(target, key);
depend.depend();
return Reflect.get(target, key, receiver);
},
set(target, key, value, receiver) {
Reflect.set(target, key, value, receiver);
const depend = getDepend(target, key);
console.log(depend.reactiveFns);
depend.notify();
},
});
const info = {
address: "深圳",
height: 1.6,
};
const infoProxy = reactive(info);
watchFn(function () {
console.log(infoProxy.address);
});
infoProxy.address = "广州";
// 简化 *** 作
const foo = reactive({
name: "foo",
});
watchFn(function () {
console.log(foo.name + " hello");
});
foo.name = "bar";
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)