Vue 2.0的学习笔记: Vue中的代理Proxy

发布于 大漠

通过一段时间的学习,我们知道如何直接访问数据属性、方法、计算属性和观察者,而这些都没有任何的前缀。现在,我们终于可以更详细地了解一下这幕后发生了什么?

我已经准备了一个包含三个数据属性、一个方法和一个计算属性的Vue实例的小示例。

<div id="app"></div>

let app = new Vue({
    el: '#app',
    data () {
        return {
            firstName: '大漠',
            lastName: 'W3cplus',
            axisX: 1,
            axisY: 2
        }
    },
    methods: {
        fullName: function () {
            return this.firstName + '-' + this.lastName
        }
    },
    computed: {
        axisZ: function () {
            return this.axisX + this.axisY
        }
    }
})

这些都不是实际使用的,因为除了Vue实际挂载元素div#app之外,模板是空的。那是因为,我们大部分时间都将花在浏览器的控制台上。打开浏览器的控制台,在控制台中输入Vue的实例app,将会打印出Vue实例app所有信息:

Vue中的代理Proxy

首先,我们需要注意以$符号为前缀的一些属性。这些属性是我们可以访问的特殊的Vue属性,在后面的学习中,将会学到这些相关的Vue属性。在这里,我们先来看一下$options属性,它包含了数据、计算属性和方法等等。在这里我们可以找到计算属性和方法。数据属性是一个函数,因此我们不能直接看到这里的数据。

Vue中的代理Proxy

在控制台中向下滚动到Vue实例app的最后一个属性,我们可以看到我们的数据、方法和计算的属性相关信息:

Vue中的代理Proxy

正如你所见,这些在Vue实例的顶层是可用的,即使我们在嵌套对象中定义它们。这是我们为了方便而自动为我们做的事情。现在让我们关注我们的数据属性,因为这些都是最容易理解的。注意如何为每个数据属性自动添加gettersetter。这些都是代理的gettersetter。如果我们把鼠标悬浮在其中一个上面,就能看到它所起的作用。它返回_data对象中的键值,这是Vue在内部使用的属性。如果找到这个对象,可以看到它包含的东西和我们刚才看到的几乎一样。除了函数不是代理函数,而是所谓的反射函数。基本上Vue在访问或修改值时使用这些函数来检测。

Vue中的代理Proxy

但是现在需要理解的是,Vue在Vue实例的顶层公开了一些代理函数,它只是调用了响应式函数。他们所做的就是让我们能够方便地访问我们的数据、方法等等。

因此,当我们添加数据属性时,Vue为这个数据属性设置了一个代理,它调用一个响应式的gettersetter函数,当Vue数据做出任何改变都会做出响应。更重要的是,我们在数据对象中添加任何对象键都可以直接访问具有相同名称的Vue实例。这都是自动完成的。

事实上,代理函数确实是真实响应函数的代理。查看Vue在内部使用的_data属性,但也有一个$data属性,我们可以使用它来从外部访问数据。让我们先将这个对象上的firstName属性在控制台上输出:

Vue中的代理Proxy

这将会直接调用响应式getter函数,因此我们应该看到firstName数据属性的值被输出到控制台。如上图所示。

在这种情况下,不需要使用$data属性,所以我们使用代理数据属性。

Vue中的代理Proxy

我们可以看到输出的结果是完全是一样的。第二行是Vue自动提供给我们的一个方便的代理函数。这是访问数据属性、方法等正常方法。

因为Vue使用任何数据属性、方法、计算属性等,并在Vue实例的顶层添加相同名称的代理属性,因此必须注意名称的冲突。因此,这些对象中的任何键都必须在所有对象中是唯一的。因此,如果你有一个firstName的数据属性,那么就不能拥有相同的计算属性或方法的名称。如果这样做了,控制台就会报出一个警告的信息。

...
methods: {
    fullName: function () {
        return this.firstName + '-' + this.lastName
    },
    firstName: function () {
        return this.firstName
    }
},
...

Vue将在处理传递给Vue构造函数的对象时替换任何现有的代理属性。很明显,如果你尝试使用这些重写的属性,这会破坏你的代码。

如果将声明的数据对象作为一个变量并将其传到Vue实例,就可以将Vue实例上的firstName和数据变量中的一个进行比较。

let data = {
    firstName: '大漠',
    lastName: 'W3cplus',
    axisX: 1,
    axisY: 2
}
let app = new Vue({
    el: '#app',
    data: data,
    methods: {
        fullName: function () {
            return this.firstName + '-' + this.lastName
        }
    },
    computed: {
        axisZ: function () {
            return this.axisX + this.axisY
        }
    }
})

将这两个属性进行比较,结果告诉我们,它们实际上是相同的。

Vue中的代理Proxy

我们还可以将data变量和Vue实例上的$data变量进行比较:

Vue中的代理Proxy

这篇文章介绍的了解了Vue中的代理属性。通过对其学习,可以了解Vue之后的一些背后原理。事实上,JavaScript中的Proxy代理在Vue源码中起着至关重要的作用。如果我们去读Vue的源码,能看到有关于JavaScript的ProxyReflection相关的身影。如果你跟我一样,对这方面不太了解,建议你阅读前几天整理的两篇文章。

由于作者也是Vue的初学者,如果文章中有何不对之处,烦请各路大婶拍正,或者你有更好的经验或建议分享,欢迎在下面的评论中与我们一起分享。

大漠

常用昵称“大漠”,W3CPlus创始人,目前就职于手淘。对HTML5、CSS3和Sass等前端脚本语言有非常深入的认识和丰富的实践经验,尤其专注对CSS3的研究,是国内最早研究和使用CSS3技术的一批人。CSS3、Sass和Drupal中国布道者。2014年出版《图解CSS3:核心技术与案例实战》。

如需转载,烦请注明出处:https://www.fedev.cn/vue/vue-proxying.htmlJordan Jumpman Pro AJ12.5