这篇文章主要介绍了Vue3的响应式机制怎么实现的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇Vue3的响应式机制怎么实现文章都会有所收获,下面我们一起来看看吧。在javascript中的变量是没有响应式这么一个概念的,代码的执行逻辑都是自上而下的,而在Vue框架中,响应式是特色功能之一。我们先看个例子可以很明显看出来double这个变量和num这个变量的关系并不是响应式的,如果我们将计算double的逻辑封装成一个函数,当num这个变量的值改变,我们就重新执行这个函数,这样double的值就会随着num的改变而改变,也就是我们俗称的响应式的。虽然实际开发的过程中会比现在这样简单的情况复杂很多,但是就是可以封装成一个函数去实现,现在的问题就在于我们如何使得double的值会根据num变量的改变而重新计算呢?如果每一次修改num变量的值,getDouble这个函数都能知道并且执行,根据num变量的改变而给double也相应的发生改变,这样就是一个响应式的雏形了。在Vue中使用过三种响应式解决方案,分别是defineProperty、 Proxy 和value setter。在Vue2中是使用了 defineProperty API,在这之前的文章中有过较为详细的描述,想了解Vue2响应式的小伙伴戳这里—>vue响应式原理 | vue2篇在 Vue2 中核心部分就在于 defineProperty 这个数据劫持 API ,当我们定义一个对象obj,使用 defineProperty 代理 num 属性,读取 num 属性时执行了 get 函数,修改num属性时执行了 set 函数,我们只需要将计算 double 的逻辑写在 set 函数中,就可以使得每次 num 改变时, double 被相应的赋值,也就是响应式。defineProperty缺陷:当我们删除obj.num属性时,set函数不会执行,所以在Vue2中我们需要一个$delete
一个专门的函数去删除数据。并且obj对象中不存在的属性无法被劫持,并且修改数组上的length属性也是无效的。单从 Proxy 的名字我们可以看出它是代理的意思,而 Proxy 的重要意义是解决了 Vue2 响应式的缺陷。Proxy用法:Proxy 对象的所有用法,都是上面这种形式,不同的只是handler参数的写法。其中,new Proxy() 表示生成一个Proxy实例,target参数表示所要拦截的目标对象,handler参数也是一个对象,用来定制拦截行为。在 Proxy 身上支持13种定制拦截get(target, propKey, receiver) :拦截对象属性的读取,比如proxy.foo
和proxy['foo']
。set(target, propKey, value, receiver) :拦截对象属性的设置,比如proxy.foo = v
或proxy['foo'] = v
,返回一个布尔值。has(target, propKey) :拦截propKey in proxy
的操作,返回一个布尔值。deleteProperty(target, propKey) :拦截delete proxy[propKey]
的操作,返回一个布尔值。ownKeys(target) :拦截Object.getOwnPropertyNames(proxy)
、Object.getOwnPropertySymbols(proxy)
、Object.keys(proxy)
、for...in
循环,返回一个数组。该方法返回目标对象所有自身的属性的属性名,而Object.keys()
的返回结果仅包括目标对象自身的可遍历属性。getOwnPropertyDescriptor(target, propKey) :拦截Object.getOwnPropertyDescriptor(proxy, propKey)
,返回属性的描述对象。defineProperty(target, propKey, propDesc) :拦截Object.defineProperty(proxy, propKey, propDesc)
、Object.defineProperties(proxy, propDescs)
,返回一个布尔值。preventExtensions(target) :拦截Object.preventExtensions(proxy)
,返回一个布尔值。getPrototypeOf(target) :拦截Object.getPrototypeOf(proxy)
,返回一个对象。isExtensible(target) :拦截Object.isExtensible(proxy)
,返回一个布尔值。setPrototypeOf(target, proto) :拦截Object.setPrototypeOf(proxy, proto)
,返回一个布尔值。如果目标对象是函数,那么还有两种额外操作可以拦截。apply(target, object, args) :拦截 Proxy 实例作为函数调用的操作,比如proxy(...args)
、proxy.call(object, ...args)
、proxy.apply(...)
。construct(target, args) :拦截 Proxy 实例作为构造函数调用的操作,比如new proxy(...args)
。在ES6中官方新定义了 免费云主机域名Reflect 对象,在ES6之前对象上的所有的方法都是直接挂载在对象这个构造函数的原型身上,而未来对象可能还会有很多方法,如果全部挂载在原型上会显得比较臃肿,而 Reflect 对象就是为了分担 Object的压力。(1) 将Object
对象的一
些明显属于语言内部的方法(比如Object.defineProperty
),放到Reflect
对象上现阶段,某些方法同时在Object
和Reflect
对象上部署,未来的新方法将只部署在Reflect
对象上。也就是说,从Reflect
对象上可以拿到语言内部的方法。(2) 修改某些Object
方法的返回结果,让其变得更合理。比如,Object.defineProperty(obj, name, desc)
在无法定义属性时,会抛出一个错误,而Reflect.defineProperty(obj, name, desc)
则会返回false
。(3) 让Object
操作都变成函数行为。某些Object
操作是命令式,比如name in obj
和delete obj[name]
,而Reflect.has(obj, name)
和Reflect.deleteProperty(obj, name)
让它们变成了函数行为。(4)Reflect
对象的方法与Proxy
对象的方法一一对应,只要是Proxy
对象的方法,就能在Reflect
对象上找到对应的方法。这就让Proxy
对象可以方便地调用对应的Reflect
方法,完成默认行为,作为修改行为的基础。也就是说,不管Proxy
怎么修改默认行为,你总可以在Reflect
上获取默认行为。所以我们在这里会使用到 Proxy 和 Reflect 对象的方与 Proxy 一一对应这一特性,来实现Vue3的响应式原理。在Vue3中响应式的核心方法是根据我们前面所做的铺垫,所以我们会使用 Proxy
代理我们所需要的相应的对象,同时使用 Reflect
对象来映射。所以我们先初步实现一下,再慢慢优化,尽可能全面。判断是否为对象(方法不唯一,有多种方法)尽可能采用函数式编程,让每一个函数只做一件事,逻辑更加清晰。但是这样会有一个问题,如果我需要代理的对象是深层嵌套的对象呢?我们先看看效果当我们深层代理时,我们直接修改深层对象中的属性并不会触发 Proxy 对象中的 set 方法,那为什么我们可以修改呢?其实就是直接访问原对象中深层对象的值并修改了,那我们如何优化这个问题呢?那也需要用到递归操作,判断深层对象是否被代理了,如果没有再执行reactive将内部未被代理的对象代理。那么我们在 get 方法内部就不能直接将映射之后的 res 返回出去了这样我们就实现了对象的深层代理,并且只有当我们访问到内部嵌套的对象时我们才
会去递归调用reactive ,这样不仅可以实现深层代理,并且节约了性能,但是其实我们还没有彻底完善,我们来看看下面这段代码这样是不是合法的,当然是合法的,但是没有必要也没有意义,所以为了避免被代理过的对象,再次被代理,太浪费性能,所以我们需要将被代理的对象打上标记,这样当带被代理过的对象访问到时,直接将被代理过的对象返回,不需要再次代理。在 Vue3 中,使用了hash表做映射,来记录是否已经被代理了。
letProxyObj=newProxy(target,handler);//被代理过的对象 toProxy.set(target,ProxyObj); toRow.set(ProxyObj.target); returnProxyObj;
letByProxy=toProxy.get(target); //防止多次代理 if(ByProxy){//如果在WeakMap中可以取到值,则说明已经被代理过了,直接返回被代理过的对象 returnByProxy; } //防止多层代理 if(toRow.get(target)){ returntarget } //为了防止下面这种写法(多层代理) //letproxy2=reactive(proxy); //letproxy3=reactive(proxy2); //其实本质上与下面这种写法没有区别(多次代理) //reactive(proxy); //reactive(proxy); //reactive(proxy);
与 Vue2 的数据劫持相比,Vue3 中的 Proxy 可以直接修改数组的长度,但是这样我们需要在 set 方法中判断我们是要在代理对象身上添加属性还是修改属性。因为更新视图的函数会在set函数中调用,我们向数组中进行操作会触发两次更新视图,所以我们需要做一些优化。避免多次更新视图,比如修改的值与原来一致就不更新视图,在上面两个判断条件中添加更新视图的函数,就不会多次更新视图。在IE11以下的浏览器都不兼容,所以如果使用 Vue3 开发一个单页应用的项目,需要考虑到兼容性问题,需要我们做额外的很多操作,才能使得IE11 以下的版本能够兼容。关于“Vue3的响应式机制怎么实现”这篇文章的内容就介绍到这里,感谢各位的阅读!相信大家对“Vue3的响应式机制怎么实现”知识都有一定的了解,大家如果还想学习更多知识,欢迎关注百云主机行业资讯频道。
这篇文章主要介绍了怎么使用node.js实现网站登录注册功能的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇怎么使用node.js实现网站登录注册功能文章都会有所收获,下面我们一起来看看吧。效果如下主入口app.jsapp.js为程…
免责声明:本站发布的图片视频文字,以转载和分享为主,文章观点不代表本站立场,本站不承担相关法律责任;如果涉及侵权请联系邮箱:360163164@qq.com举报,并提供相关证据,经查实将立刻删除涉嫌侵权内容。