Vue.js Proxying
Throughout this series, we have seen how we can access data properties, methods, computed properties and watchers directly without any prefix. Now it’s finally time to take a look at what happens behind the scenes in a little more detail.
I have prepared a small example with a Vue instance containing a couple of data properties, a method and a computed property.
<div id="app"></div>
var vm = new Vue({
el: '#app',
data: {
message: 'Hello World!',
x: 1,
y: 2
},
methods: {
showMessage: function() {
alert(this.message);
}
},
computed: {
z: function() {
return this.x + this.y;
}
}
});
console.log(vm);
None of these are actually used for anything because the template is empty except for the element that the Vue instance is attached to. This is because we’ll actually be spending our time within the browser’s console in this lecture. That’s also why I have added a line that logs the Vue instance to the console. So let’s open it up and run the code.
First, notice how some properties are prefixed with a dollar sign. These are special Vue properties that we can access, and we are going to take a look at some of these later in this series. Let’s first take a look at the $options property, which contains our data, computed properties, methods, and more. Here we can find our computed property and method. The data property is a function, so we cannot see the data directly here. We will get back to why this is the case later in the series.
If we scroll down to the last properties of the Vue instance, we will find our data, methods and computed property.
As you can see, these are available at the top level of the Vue instance, even though we defined them within nested objects. This is something Vue does for us automatically for our convenience. Let’s focus on our data properties for now, as these are simplest to understand. Notice how getters and setters have been added automatically for each of our data properties. These are so-called proxy getters and proxy setters. If I hover my mouse over one of them, notice what it does. It returns the value of the key within the _data object, which is a property that Vue uses internally. If I find this object, we can see that it contains pretty much the same thing as we just saw, except that the functions are not proxy functions, but so-called reactive functions. We are going to take a closer look at what these functions do in the next post, but basically Vue uses these functions for detecting when we access or modify values.
What’s important to understand now, though, is that Vue exposes some proxy functions at the top level of the Vue instance, which simply invoke reactive functions. So all they do, is to enable us to conveniently access our data, methods, and more.
So when we add data properties, for instance, Vue.js sets up a proxy for this data property, which invokes a reactive getter or setter function, which enables Vue.js to react to any changes that we make to the data. More on that in the next post, though; the important thing to know, is that any object key that we add within our data object, for example, is accessible directly on the Vue instance with the same name. That’s all done for us automatically.
Now I just want to show you that the proxy functions are indeed just proxies to the real reactive functions. We took a look at the _data property which Vue uses internally, but there is also a $data property which we can use to access our data “from the outside,” so to speak. Let’s log the message property on this object to the console first of all.
console.log(vm.$data.message);
This will invoke the reactive getter function directly, so we should see the value of our message data property being output to the console.
In this case there is really no need to make use of the $data property, so let’s use the proxied data property.
console.log(vm.message);
We can see that the result of these two lines are exactly the same. The second line is just a convenient proxy function that Vue automatically made available to us, and this is the normal way to access data properties, methods, etc.
Because Vue takes any data property, method, computed property, etc. and adds a proxy property of the same name at the top level of the Vue instance, you have to be careful about name collissions. Therefore any key within these objects must be unique across all of the objects. So if you have a data property named “message,” for instance, then you cannot have a computed property or method named the same. If you do this, you will see a warning in the console, and Vue will replace any existing proxy property as it processes the object passed to the Vue constructor. Obviously this would break your code if you tried to use these overwritten properties.
If we declare the data object as a variable and pass it into the Vue instance, we can compare the message property on the Vue instance with the one on the data variable.
var data = {
message: 'Hello World!',
x: 1,
y: 2
};
var vm = new Vue({
data: data
// ...
});
Let’s compare the the two properties to the console and see that they are indeed identical.
console.log(data.message === vm.message);
Let’s also compare the data variable as a whole with the $data variable on the Vue instance.
console.log(data === vm.$data);
And indeed this yields true as well.
Now that we covered how Vue.js proxies properties, let’s now take a look at how it watches them for changes.
Here is what you will learn:
- How to build advanced Vue.js applications (including SPA)
- How Vue.js works under the hood
- Communicating with services through HTTP
- Managing state of large applications with Vuex
- ... and much more!
One comment on »Vue.js Proxying«
Hello Bo, thank you for this post. I understand the idea behind using a proxy but there is no simple practical example I have seen so far. Could you kindly give one.