揭秘vue3.0为什么用proxy代替defineProperty

来源:程序思维浏览:1738次

如果你对Vue发布订阅的响应式实现有一定的了解,那么你一定知道defineProperty。

Object.defineProperty(obj, prop, descriptor)

Vue2.x中的响应式实现正是基于defineProperty中的descriptor,通过属性的getter、setter监听来实现的。

同时你应该知道的是,我们在Vue中使用下标的方式直接修改属性的值或者添加一个预先不存在的对象属性是无法做到setter监听的,这是defineProperty的局限性。

而我们在Vue中使用的push、pop、shift、unshift、splice等一系列修改原数组的方法,其实不是原生的数组方法,都是被Vue修改过的,其中加入了响应代码。

有消息称Vue3.0的响应式将会使用Proxy来实现,这一举动无疑优化了Vue的响应能力,但是也决定了Vue将会彻底抛弃IE阵营,我们是否应该默(qing)哀(zhu) 一分钟。

defineProperty中的getter、setter

defineProperty的局限性的最大原因是它只能针对单例属性做监听,Vue2.x中对data中的属性做了遍历 + 递归,为每个属性设置了getter、setter。

这也就是为什么Vue只能对data中预定义过的属性做出响应的原因。

defineProperty的用法

    var val = 1
    var obj = Object.defineProperty({}, 'sum', {
        enumerable: true,
        configurable: true,
        get() {
            return val
        },
        set(newValue) {
            val += newValue
        }
    })

测试代码:



我们也可以这样写:

    var val = 1
    var obj = {
        get ['sum']() {
            return val
        },
        set ['sum'](newValue) {
            val += newValue
        }
    }

复制代码这段代码和上面代码结果是一样的。

这里的'sum'就是被监听的属性名,也就是我们需要监听的“一个”属性。

正是因为使用defineProperty每次只能绑定一个属性监听,所以Vue在遍历 + 递归时要有更大的性能消耗和更多的代码。

Proxy中的getter、setter

Vue3.0终于要使用Proxy,就像上文说的一样,首先应该对IE表示沉(xi)痛(wen)哀(le)悼(jian)。

Proxy 可以理解成,在目标对象之前架设一层“拦截”,外界对该对象的访问,都必须先通过这层拦截,因此提供了一种机制,可以对外界的访问进行过滤和改写。

也就是说,Proxy的监听是针对一个对象的,那么对这个对象的所有操作会进入监听操作,这就完全可以代理所有属性了。

使用Proxy监听

var data = {
        sum: 0
    }
    var proxy = new Proxy(data, {
        get(target, property) {
            return target[property]
        },
        set(target, property, value) {
            target[property] += value
        }
    })

Proxy测试



当data为数组时:



Proxy中getter、setter说明

get接收三个参数: get(target, propKey, receiver)

target是被监听对象,在示例代码中表示的是data

propKey是属性名,即当前需要获取的属性名

receiver是监听对象,即Proxy实例,在示例代码中表示的是proxy

set接收四个参数: get(target, propKey, value, receiver)

target、 propKey、receiver三个参数和get中一样

value表示被修改的值,即测试代码中的1

很明显的是,我们使用Proxy时并不需要关心某一个具体的属性,并且Proxy实例上的修改不会影响到被监听对象target中的值(前提是你不主动修改target)。

Proxy中getter、setter的局限性

让我们看看以下代码:

    var data = {
        a: { b: 0 }
    }
    var proxy = new Proxy(data, {
        get(target, property) {
            console.log(`path: ${property}`)
            return target[property]
        },
        set(target, property, value) {
            console.log(`path: ${property}`)
            target[property] += value
        }
    })

打印结果:



很明显的是,proxy代理getter、setter只会关注浅层数据,而不会返回深层路径。

如果path在这里能够返回a.b那么将会带来一个很好的收益,不过既然Proxy规范没有实现那么我们也是无计可施。

而且从理解上来说修改proxy.a.b返回的修改对象名是a貌似也是正确的,现在我们需要做的是记住这一结论就好。

总结:

Proxy和defineProperty中getter、setter的用法就说到这里。

可以预见的是,Vue3.0中使用Proxy代理将会带来很大的性能提升和更优的代码。

但是就像react中约定的一样,对于引用类型值的响应式的支持可能会变得比以前更不友好(需要开发者实现浅拷贝赋值)。

不过如果尤大依旧选择使用递归的方式来解决对象类型数据的响应式,我个人看来是有些得不偿失的。

从我自己的意愿来看,我更希望是借助于immutable,而不是走递归遍历的老路。

相信尤大一定会有自己的考量,最终的结果肯定是令大部分人满意的方案。

同时Vue3支持typescript的方向更是令我激动不已,作为尤大的粉丝,我们好好期待就是了。
精品好课
jQuery视频教程从入门到精通
jquery视频教程从入门到精通,课程主要包含:jquery选择器、jquery事件、jquery文档操作、动画、Ajax、jquery插件的制作、jquery下拉无限加载插件的制作等等......
Vue2+Vue3+ES6+TS+Uni-app开发微信小程序从入门到实战视频教程
2021年最新Vue2+Vue3+ES6+TypeScript和uni-app开发微信小程序从入门到实战视频教程,本课程教你如何快速学会VUE和uni-app并应用到实战,教你如何解决内存泄漏,常用UI库的使用,自己...
VUE2+VUE3视频教程从入门到精通(全网最全的Vue课程)
VUE是目前最火的前端框架之一,就业薪资很高,本课程教您如何快速学会VUE+ES6并应用到实战,教你如何解决内存泄漏,常用UI库的使用,自己封装组件,正式上线白屏问题,性能优化等。对正在工作当中或打算学习VUE高薪就...
最新完整React+VUE视频教程从入门到精,企业级实战项目
React和VUE是目前最火的前端框架,就业薪资很高,本课程教您如何快速学会React和VUE并应用到实战,教你如何解决内存泄漏,常用库的使用,自己封装组件,正式上线白屏问题,性能优化等。对正在工作当中或打算学习Re...
React实战视频教程仿京东移动端电商
React是前端最火的框架之一,就业薪资很高,本课程教您如何快速学会React并应用到实战,对正在工作当中或打算学习React高薪就业的你来说,那么这门课程便是你手中的葵花宝典。
HTML5视频播放器video开发教程
适用人群1、有html基础2、有css基础3、有javascript基础课程概述手把手教你如何开发属于自己的HTML5视频播放器,利用mp4转成m3u8格式的视频,并在移动端和PC端进行播放支持m3u8直播格式,兼容...
最新完整React视频教程从入门到精通纯干货纯实战
React是目前最火的前端框架,就业薪资很高,本课程教您如何快速学会React并应用到实战,教你如何解决内存泄漏,常用UI库的使用,自己封装组件,正式上线白屏问题,性能优化等。对正在工作当中或打算学习React高薪就...
HTML5基础入门视频教程易学必会
HTML5基础入门视频教程,教学思路清晰,简单易学必会。适合人群:创业者,只要会打字,对互联网编程感兴趣都可以学。课程概述:该课程主要讲解HTML(学习HTML5的必备基础语言)、CSS3、Javascript(学习...
收藏
扫一扫关注我们