基于Proxy

// 弱引用映射表 es6 防止对象不能被回收
let toProxy = new WeakMap(); // 原对象: 代理过得对象
let toRaw = new WeakMap(); // 被代理过的对象: 原对象 // 判断为对象
function isObject(val) {
return typeof val === 'object' && val !== null
}
// 区分改变数组长度还是数值
function hasOwn(target, key) {
return target.hasOwnProperty(key)
} function reactive(target) {
// 创建响应式对象
return createReactiveObject(target)
}
// 创建响应式对象
function createReactiveObject(target) {
if (!isObject(target)) {
return target
}
let proxy = toProxy.get(target); // 如果已经代理过 直接返回代理结果
if (proxy) {
return proxy;
}
if (toRaw.has(target)) { // 防止对象被多次代理
return target;
}
let baseHandler = {
// Reflect优点: 不报错 有返回值 会替代Object 上的方法
// Proxy + reflect 反射
get(target, key, receiver) {
// console.log('查询');
let result = Reflect.get(target, key, receiver);
// 收集依赖订阅 把当前key 和effect对应
track(target, key);
// result 当前获取到的值
return isObject(result) ? reactive(result) : result; // 深层次代理 多层代理 (递归)
},
set(target, key, value, receiver) {
// console.log('设置');
// 区分改变数组长度还是数值
let hadKey = hasOwn(target, key);
let oldValue = target[key];
let res = Reflect.set(target, key, value, receiver);
if (!hadKey) {
trigger(target, 'add', key);
// console.log('新增属性')
} else if (oldValue !== value) { // 表示属性修改
// console.log('修改属性')
trigger(target, 'set', key);
}//
// 设置成功返回值
return res;
},
deleteProperty(target, key) {
// console.log('删除');
let res = Reflect.deleteProperty(target, key)
return res;
}
}
let observed = new Proxy(target, baseHandler);
toProxy.set(target, observed);
toRaw.set(observed, target);
return observed
} // let proxy = reactive({name: {n: 'wyq'}});
// proxy.name.n = '王瘦瘦'
// console.log(proxy.name.n)
// let arr = [1, 2, 3];
// let proxy = reactive(arr)
// proxy.length = 100; // 发布订阅模式
// 栈结构
let activeEffectStacks = []; // 栈型结果
let targetsMap = new WeakMap(); // 集合和哈希表
function track(target, key) { // target中的key变化 执行数组方法
let effect = activeEffectStacks[activeEffectStacks.length - 1];
if (effect) { // 有对应关系 创建关联
let depsMap = targetsMap.get(target);
if (!depsMap) {
targetsMap.set(target, depsMap = new Map());
}
let deps = depsMap.get(key);
if (!deps) {
depsMap.set(key, deps = new Set());
}
if (!deps.has(effect)) {
deps.add(effect);
}
// 动态创建依赖关系
}
// 不管
} function trigger(target, type, key) {
let depsMap = targetsMap.get(target);
if (depsMap) {
let deps = depsMap.get(key);
if (deps) { // 当前key 对应effect 依次执行
deps.forEach((effect) => {
effect();
})
}
}
} // 响应式 副作用
function effect(fn) {
// 把fn包装成响应式函数
let effect = createReactiveEffect(fn);
effect(); // 先执行一次
} function createReactiveEffect(fn) {
// 高阶函数
let effect = function () { // is 创建的响应式的effect
return run(effect , fn); // 1.让fn执行 2.存入栈
};
return effect;
} function run(effect, fn) {
try {
activeEffectStacks.push(effect);
fn();
}finally {
activeEffectStacks.pop();
}
} let obj = reactive({name: 'wyq'});
effect(() => { // effect默认执行两次 默认先执行一次 依赖数据变化在执行一次
console.log(obj.name)
});
obj.name = '王瘦瘦';
obj.name = '王瘦瘦';
obj.name = 'SpongeBob';

  

Vue3.0响应式实现的更多相关文章

  1. Vue3.0工程创建 && setup、ref、reactive函数 && Vue3.0响应式实现原理

    1 # 一.创建Vue3.0工程 2 # 1.使用vue-cli创建 3 # 官方文档: https://cli.vuejs.org/zh/guide/creating-a-project.html# ...

  2. Vue3.0响应式原理

    Vue3.0的响应式基于Proxy实现.具体代码如下: 1 let targetMap = new WeakMap() 2 let effectStack = [] //存储副作用 3 4 const ...

  3. Vue3.0 响应式数据原理:ES6 Proxy

    Vue3.0 开始用 Proxy 代替 Object.defineProperty了,这篇文章结合实例教你如何使用Proxy 本篇文章同时收录[前端知识点]中,链接直达 阅读本文您将收获 JavaSc ...

  4. vue2.0与3.0响应式原理机制

    vue2.0响应式原理 - defineProperty 这个原理老生常谈了,就是拦截对象,给对象的属性增加set 和 get方法,因为核心是defineProperty所以还需要对数组的方法进行拦截 ...

  5. 简单对比vue2.x与vue3.x响应式及新功能

    简单对比vue2.x与vue3.x响应式 对响应方式来讲:Vue3.x 将使用Proxy ,取代Vue2.x 版本的 Object.defineProperty. 为何要将Object.defineP ...

  6. 【SpringBoot】SpringBoot2.0响应式编程

    ========================15.高级篇幅之SpringBoot2.0响应式编程 ================================ 1.SprinBoot2.x响应 ...

  7. Vue 2.0 与 Vue 3.0 响应式原理比较

    Vue 2.0 的响应式是基于Object.defineProperty实现的 当你把一个普通的 JavaScript 对象传入 Vue 实例作为 data 选项,Vue 将遍历此对象所有的 prop ...

  8. vue2与vue3实现响应式的原理区别和提升

    区别: vue2.x: 实现原理: 对象类型:Object.defineProperty()对属性的读取,修改进行拦截(数据劫持): 数组类型:通过重写更新数组的一系列方法来进行拦截(对数组的变更方法 ...

  9. JuCheap V2.0响应式后台管理系统模板正式发布beta版本

    JuCheap V1.* 查看地址: http://blog.csdn.net/allenwdj/article/details/49155339 经过半年的努力,JuCheap后台通用响应式管理后台 ...

随机推荐

  1. 浏览器是怎样工作的:渲染引擎,HTML解析(连载二)

    转载自:http://ued.ctrip.com/blog/how-browsers-work-rendering-engine-html-parsing-series-ii.html 渲染引擎 渲染 ...

  2. 一步一步玩控件:自定义TabControl——从山寨Safari开始

    作者:野比 (conmajia@gmail.com) 时间:May, 2012 封面图片为野比原创,请勿未经允许私自引用 #1-1 嗯,各位,又是我,生物钟颠倒的家伙. 今天我要山寨的是大名鼎鼎的Ap ...

  3. C# 委托 线程 窗体假死

    转载:http://www.cnblogs.com/smartls/archive/2011/04/08/2008981.html 异步调用是CLR为开发者提供的一种重要的编程手段,它也是构建高性能. ...

  4. 帝国CMS自定义页面的添加与目录式链接的处理

    需求: 1.将某一本地前端自定义页面模板,导入到帝国系统,应用到网站 2.将导入的页面在站点中打开为目录式链接 www.abc.com/softlink/ 环境: 1.windows服务器 2.帝国C ...

  5. vue.js(12)--过滤器

    vue中的全局过滤器与定义私有过滤器 全局过滤器 <!DOCTYPE html> <html lang="en"> <head> <met ...

  6. 2018-8-28-win10-uwp-MVVM入门

    title author date CreateTime categories win10 uwp MVVM入门 lindexi 2018-08-28 15:37:52 +0800 2018-2-13 ...

  7. 82-基于Xilinx Virtex-5LXT FPGA的四路光纤PCIE卡(4路光纤卡)

    基于Xilinx Virtex-5LXT FPGA的四路光纤PCIE卡(4路光纤卡) 1.板卡特点: 1)  主芯片采用Xilinx Virtex-5LXT FPGA. 前面板提供4路光纤接口,速率可 ...

  8. Taro -- 微信小程序密码弹窗

    记录一个类似支付密码的弹窗写法,实现是否免密功能.如图: index.js   import Taro, { Component } from '@tarojs/taro'   import { Vi ...

  9. rabbitma客户端

    知道答案了,原因是重连的时候,每次重连都创建了一个新的线程,然后有信号的时候,每个线程都连接到rabbitMq服务器上去,导致了同一个IP通过不同端口链接上了服务器,出现了多个channel,而发多次 ...

  10. 三、ARM 寄存器及异常处理

    3.1 ARM 内部寄存器 ARM920T 总共有 37 个寄存器,其中 31 通用 32 位寄存器和 6 个状态寄存器,但不能在同一时刻对所有的寄存器可见.处理器状态和运行模式决定了哪些寄存器对程序 ...