Vue3.0响应式实现
基于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响应式实现的更多相关文章
- 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# ...
- Vue3.0响应式原理
Vue3.0的响应式基于Proxy实现.具体代码如下: 1 let targetMap = new WeakMap() 2 let effectStack = [] //存储副作用 3 4 const ...
- Vue3.0 响应式数据原理:ES6 Proxy
Vue3.0 开始用 Proxy 代替 Object.defineProperty了,这篇文章结合实例教你如何使用Proxy 本篇文章同时收录[前端知识点]中,链接直达 阅读本文您将收获 JavaSc ...
- vue2.0与3.0响应式原理机制
vue2.0响应式原理 - defineProperty 这个原理老生常谈了,就是拦截对象,给对象的属性增加set 和 get方法,因为核心是defineProperty所以还需要对数组的方法进行拦截 ...
- 简单对比vue2.x与vue3.x响应式及新功能
简单对比vue2.x与vue3.x响应式 对响应方式来讲:Vue3.x 将使用Proxy ,取代Vue2.x 版本的 Object.defineProperty. 为何要将Object.defineP ...
- 【SpringBoot】SpringBoot2.0响应式编程
========================15.高级篇幅之SpringBoot2.0响应式编程 ================================ 1.SprinBoot2.x响应 ...
- Vue 2.0 与 Vue 3.0 响应式原理比较
Vue 2.0 的响应式是基于Object.defineProperty实现的 当你把一个普通的 JavaScript 对象传入 Vue 实例作为 data 选项,Vue 将遍历此对象所有的 prop ...
- vue2与vue3实现响应式的原理区别和提升
区别: vue2.x: 实现原理: 对象类型:Object.defineProperty()对属性的读取,修改进行拦截(数据劫持): 数组类型:通过重写更新数组的一系列方法来进行拦截(对数组的变更方法 ...
- JuCheap V2.0响应式后台管理系统模板正式发布beta版本
JuCheap V1.* 查看地址: http://blog.csdn.net/allenwdj/article/details/49155339 经过半年的努力,JuCheap后台通用响应式管理后台 ...
随机推荐
- 12-jQuery获取相关尺寸
# 相关尺寸 **获取元素相对于文档的偏移量** > var pos = $('#small').offset(); >> // console.log(pos.left);// c ...
- SSM商城系统开发笔记-问题02- Error creating bean with name 'userController'
Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean wit ...
- service worker介绍
原文:Service workers explained 译者:neal1991 welcome to star my articles-translator, providing you advan ...
- python基础--文件的操作
#r w a 文件读取操作 默认打开为读操作 #f=open('coldplay.txt','r',encoding="utf-8")#open函数默认已系统编码方式打开windo ...
- web项目分层设计
model.dao.service.controller之间的关系,还有util和task的简介 model: 与数据库中的表一一对应,实现set和get的方法.
- JAVA中的反射机制 详解
主要介绍以下几方面内容 理解 Class 类 理解 Java 的类加载机制 学会使用 ClassLoader 进行类加载 理解反射的机制 掌握 Constructor.Method.Field 类的用 ...
- 【leetcode】1042. Flower Planting With No Adjacent
题目如下: You have N gardens, labelled 1 to N. In each garden, you want to plant one of 4 types of flow ...
- iOS项目自动打包
用的是:https://www.jianshu.com/p/a61fe38c8c29 需要上传到pgy /TestFlight 在脚本中加几句就可以了 另外一种方式,fastlane打包 首要条件: ...
- python 生成多维数组
在刷题时用到了数组,因为不提供三方库所以不能使用Numpy.想如何通过python列表模拟数组. 第一种方法 """ 生成n*m的初始值为0的矩阵 "" ...
- 状压DP常用操作
1. 判断一个数字x二进制下第i位是不是等于1. 方法:if ( ( ( 1 << ( i - 1 ) ) & x ) > 0) 将1左移i-1位,相当于制造了一个只有第i位 ...