vue2响应式原理
主要使用Object的defineProperty为每个属性添加get和set操作,在get和set中添加拦截或者是数据渲染
简单实现//监听
function observe(target) { if (typeof target !== "object" || target === "null") { return; } //遍历添加get set 属性 for (let key in target) { defObserve(target, key, target[key]); } } function defObserve(target, key, value) { debugger; observe(value); //递归遍历 Object.defineProperty(target, key, { get() { console.log("获取数据"); return value; }, set(newValue) { if (newValue !== value) { console.log("设置数据"); renser(); value = newValue; } }, }); } //渲染数据 function renser() { console.log("渲染数据"); } let obj = { name: "zhangsan", };
observe(obj);
obj.name.a = "lisi";
console.log(obj.name.a);
//获取数据;
// 设置数据;
// 渲染数据;
// 获取数据;
// 获取数据;
// lisi;
因为obj.name时也触发一次get,所以获取数据第一次就输出了,至此对象的数据响应实现了,还有数组需要特殊处理。
添加数组响应式,就是对原数组进行拦截
const arrayMap = [ "push", "pop", "shift", "unshift", "slice", "splice", "reverse", ]; //还有其它方法此处不定义 const oldArrayPropoty = Array.prototype; const newArrayPropoty = Object.create(oldArrayPropoty); arrayMap.forEach((method) => { newArrayPropoty[method] = function() { //添加拦截操作 render(); //依旧执行数组原有方法 oldArrayPropoty[method].call(this, ...arguments); }; }); //监听 function observe(target) { //判断是否是对象 if (typeof target !== "object" || target === "null") { return; } //判断是否是数组 if (Array.isArray(target)) { //绑定__proto__为newArrayPropoty // target.__proto__ = newArrayPropoty; //同理 Object.setPrototypeOf(target, newArrayPropoty); } //遍历添加get set 属性 for (let key in target) { //若是数组,会为每个方法添加get和set defObserve(target, key, target[key]); } } function defObserve(target, key, value) { observe(value); //递归遍历 Object.defineProperty(target, key, { get() { console.log("获取数据"); return value; }, set(newValue) { if (newValue !== value) { console.log("设置数据"); render(); value = newValue; } }, }); } //渲染数据 function render() { console.log("渲染数据"); } // let obj = { // name: { a: "张三" }, // }; // observe(obj); // obj.name.a = "lisi"; // console.log(obj.name.a); let arr = [1, 2, 3]; observe(arr); arr.push(4); console.log(arr);
输出打印如下
可以看到新增元素4操作数组时也触发了拦截操作,但是这里还有一个问题是当对象被重新赋值时是不会触发操作的,如obj.name={a:'王五'},此时这个a没有get和set属性,需要在set中增加一步
set(newValue) { if (newValue !== value) { console.log("设置数据"); //重新监测 observe(newValue); render(); value = newValue; } },
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通