尚硅谷大数据项目实战提升大神-窈窕淑女寤寐求之
初识VUE响应式原理
尚硅谷大数据项目实战提升大神
download:https://www.51xuebc.com/thread-524-1-1.html
自从Vue发布以来,就遭到了广阔开发人员的喜爱,提到Vue,我们首先想到的就是Vue的响应式系统,那响应式系统到底是怎样回事呢?接下来我就给大家简单引见一下Vue中的响应式原理。
vue2的响应式原理
虽然Vue2将于2023年12月31日中止维护,但是我们仍然有很多项目是基于Vue2.X停止开发的,那么我们先简单看一看Vue2.X是基于什么完成的吧~
Object.defineProperty
Vue2的响应式原理是基于对象的defineProperty()办法停止开发的,那么这个办法有什么作用呢?MDN是这样引见的:
**
object.defineProperty()办法会直接在一个对象上定义一个新属性,或者修正一个对象的现有属性,并返回此对象。
也就是说,我们能够经过对象的这个办法准确的添加或者修正对象的属性。每个对象都具有get/set属性,当访问get属性时,会调用getter办法,当对象的属性值被修正时,会调用setter办法,正式基于getter和setter办法,Vue才能够应用Object.defineProperty来完成响应式系统。
Object.defineProperty在Vue中的运用
在vue中,当把一个普通的JavaScript对象传入Vue实例作为data选项,Vue会遍历此对象的一切属性,并运用object.defineProperty将这些属性转为getter/setter,
getter/setter能够追踪依赖,在属性被访问的时分通知视图变卦。
Object.defineProperty(obj, 'targetObj', { get() { // 完成依赖搜集 }, set() { // 发作变卦,同时通知相关依赖 } })
vue3的响应式原理
vue2.0很好的完成了数据的双向绑定,但是也遗留了一个很重要的问题:由于Vue会在初始化实例时将property转化为getter/setter,所以,property必需在data对象上先存在才干让Vue将其转换为响应式数据。那么关于新增加的对象、或者某些需求特殊操作的数组想要转换为响应式数据就需求运用Vue.set等办法。
Vue3就很好的处理了这个问题。那么,Vue3是如何处理的呢?让我们就一同看看吧~
Proxy
提到Vue3的数据拦截,我们首先要理解什么是proxy?
Proxy 能够了解成,在目的对象之前架设一层“拦截”,外界对该对象的访问,都必需先经过这层拦截,因而提供了一种机制,能够对外界的访问停止过滤和改写。Proxy 这个词的原意是代理,用在这里表示由它来“代理”某些操作,能够译为“代理器”。
原来,Vue3用了Proxy代理替代了Object.defineProperty办法。同样的,在proxy中也有get/set办法,举个例子~
var obj = new Proxy({}, { get: function (target, name) { return name; }, set: function (target, key, val) { target[key] = val return target; } });
我们经过给每一个目的对象都树立一个对应的Proxy对象对其代理就能够补偿Object.defineProperty关于新增对象无法监听的缺陷。
简单设计一个Vue3的响应系统
完成一个简单的响应系统的思绪:
•读取(get)时,将反作用函数入栈;
•设置(set)时,将反作用函数出栈,执行反作用函数。
// 存储反作用函数的栈 const bucket = new Set() // 存储被注册的反作用函数 let activeEffect // 注册反作用函数 function effect (fn) { // 存储反作用函数 activeEffect = fn fn() } // 反作用函数fn effect ( () => { document.body.innerText = obj.text } )
执行匿名函数fn办法时,会触发响应式数据obj.text的读取操作,进而触发代理对象Proxy的get拦截函数:
const Proxy = new Proxy(data, { get (target, key) { if (activeEffect) { bucket.add(activeEffect) } return target[key] }, set (target, key, newVal) { target[key] = newVal bucket.forEach(fn => fn()) return true } })
到此,我们会发现,有一个疑问,我们怎样能保证修正一个属性之后触发的反作用函数是我预期想要触发的反作用函数呢?为理解决这个问题,我们还需求树立反作用函数与目的对象的联络:
我们仅需求用WeakMap替代Set数据构造:
const bucket = new WeakMap()
修正Proxy对象:
const Proxy = new Proxy(data, { get (target, key) { if (!activeEffect) return target[key] // 先从栈中取出depsMap,depsMap中保管目的对象和其相关反作用函数的一对多的关系 let depsMap = bucket.get(target) if (!depsMap) { bucket.set(target, (depsMap = new Map()) } // 再依据key从depsMap中获得deps,deps保管一切与key相关联的反作用函数 let deps = depsMap.get(key) if (!deps) { depsMap.set(key, (deps = new Set()) } deps.add(activeEffect) return target[key] }, set (target, key, newVal) { target[key] = newVal const depsMap = bucket.get(target) if (!depsMap) return const effects = depsMap.get(key) effects && effects.forEach(fn => fn()) } })
这样,我们就完成了一个简易的响应系统。那么为什么要用weakMap而不是运用Map呢?就交给大家一同考虑啦~