基于Proxy、Map、WeakMap实现响应式数据,跟着视频学习梳理思路模仿了一遍。底部为全部代码。深入JavaScript高级语法-coderwhy大神新课-学习视频教程-腾讯课堂该课程的核心目的是深入学习JavaScript的核心语法,特别是JavaScript比较复杂的、难以理解的一些概念和特性,进行深入细致的讲解。本课程能帮助你在前端技术学习、面试、工作、项目应用上,承上启下,融会贯通,不管你是前端在职工作者还是初学者,此课程都非常值得学习。https://ke.qq.com/course/3619571
思路一:
根据对象set、get实现访问修改执行对应方法,并使用Proxy代理,封装到resFunc函数中可在创建对象时直接绑定事件。
Proxy MDN
Proxy 对象用于创建一个对象的代理,从而实现基本操作的拦截和自定义(如属性查找、赋值、枚举、函数调用等)。
// 代理对象
function resFunc(obj) {
return new Proxy(obj, {
// get
get(target, key, receiver) {
return Reflect.get(target, key, receiver); //返回对应的值
},
// set
set(target, key, newValue, receiver) {
Reflect.set(target, key, newValue, receiver); //修改对应的值
}
})
}
思路二 :
保存对象的响应式方法,可以WeakMap来进行储存,(优势:可以使用对象作为key存储对应的事件)同一属性存在多个事件时,使用Map存储(优势:避免重复存储方法)。
WeakMap MDN
WeakMap
对象是一组键/值对的集合,其中的键是弱引用的。其键必须是对象,而值可以是任意的。描述:
Map MDN
Map
对象保存键值对,并且能够记住键的原始插入顺序。任何值(对象或者原始值) 都可以作为一个键或一个值。
// 处理保存的方法
const targetMap = new WeakMap() //所有的响应式方法,以对象作为key存储
//创建方法,每次调用set时保存方法
function getDepend(target, key) {
// 根据对象保存
let map = targetMap.get(target); //根据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 watchFn(fn) {
activeReactiveFn = fn
fn()
activeReactiveFn = null
}
// 测试
function test1() {
console.log(ResObj1.name);
}
watchFn(test1)
思路四:
对重复事件封装
// 创建类保存对象响应式方法
class Depend {
constructor() {
this.ResObjFunc = new Set()
}
addFunc() {
activeReactiveFn ? this.ResObjFunc.add(activeReactiveFn) : ''
}
notify() {
this.ResObjFunc.forEach(func => {
func()
})
}
}
代码完善
// 创建变量保存方法
let activeReactiveFn = null
// 创建类保存对象响应式方法
class Depend {
constructor() {
this.ResObjFunc = new Set()
}
addFunc() {
activeReactiveFn ? this.ResObjFunc.add(activeReactiveFn) : ''
}
notify() {
this.ResObjFunc.forEach(func => {
func()
})
}
}
// 处理保存的方法
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 resFunc(obj) {
return new Proxy(obj, {
// get
get(target, key, receiver) {
// 执行对应方法
const depend = getDepend(target, key);
depend.addFunc()
return Reflect.get(target, key, receiver); //返回对应的值
},
// set
set(target, key, newValue, receiver) {
Reflect.set(target, key, newValue, receiver); //修改对应的值
// 执行对应方法
const depend = getDepend(target, key);
depend.notify()
}
})
}
// 封装一个响应式的函数
function watchFn(fn) {
activeReactiveFn = fn
fn()
activeReactiveFn = null
}
// 创建响应式对象
let ResObj1 = resFunc({
name: 'pxq',
age: 18
})
// 测试
function test1() {
console.log(ResObj1.name);
}
function test2() {
console.log(ResObj1.age);
}
watchFn(test1)
watchFn(test2)
ResObj1.name = 'wxf'
ResObj1.age = 20