基于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. win32 socket 编程(三)——TCP/IP

    一.TCP/IP解析 TCP/IP协议的核心部分是传输层协议(TCP.UDP),网络层协议(IP)和物理接口层,这三层通常是在操作系统内核中实现.因此用户一般不涉及.编程时,编程界面有两种形式: 1. ...

  2. Latex--入门系列三

    Latex 专业的参考 tex对于论文写作或者其他的一些需要排版的写作来说,还是非常有意义的.我在网上看到这个对于Latex的入门介绍还是比较全面的,Arbitrary reference .所以将会 ...

  3. XMLHttpRequest.setRequestHeader()

    在AJAX中,如果需要像 HTML 表单那样 POST 数据,需要使用 setRequestHeader() 方法来添加 HTTP 头. 然后在 send() 方法中规定需要希望发送的数据: setR ...

  4. Vue/React如何优雅的一劳永逸的注册路由及组件

    原文链接: 本人掘金文章  假如图片看不清晰可前往掘金原文预览 官方文档: 组建注册 路由注册 未优化版: 在Vue官方文档 中,我们通过  Vue.component('MyComponentNam ...

  5. MongoDB的环境搭建及启动

    MongoDB环境搭建及配置 一.环境搭建 Mac:brew install mongodb 常见问题: Error: Permission denied @ unlink_internal 解决方案 ...

  6. Oracle 数字转为字符串 to_char()

    格式:TO_CHAR(number,'format_model') 9 -->Represents a number 0 --> Forces a zero to be displayed ...

  7. leetcode 实现-168.Excel表列名称

    168.Excel表列名称 描述 给定一个正整数,返回它在 Excel 表中相对应的列名称. 例如, 1 -> A 2 -> B 3 -> C … 26 -> Z 27 -&g ...

  8. oracle常用操作方法

    ---oracle创建数据库,基于plsqldev工具 1.创建表空间,创建空内容的物理文件create tablespace db_test --表空间名 datafile 'D:\test.dbf ...

  9. dsu on tree 学习笔记

    这是一个黑科技,考虑树链剖分后,每个点只会在轻重链之间转化\(log\)次. 考虑暴力是怎么写的,每次枚举一个点,再暴力把子树全部扫一边. \(dsu\ on\ tree.\)的思想就是保留重儿子不清 ...

  10. ATM机取款过程

    假设一个简单的ATM机的取款过程是这样的:首先提示用户输入密码,最多只能输入三次,超过3次则提示用户“密码错误,请取卡”结束交易.如果用户密码正确,再提示用户输入取款金额,ATM机只能输出100元的纸 ...