Today we’ll talk about vUE’s bidirectional data binding.

Changes in data

In the process of learning VUE by myself, I was surprised to find that the data transmitted to VUE would actually change! My code was as follows:

const amout = {n:1}

console.log(amout)  // {n:1}

new Vue({
  data:amout,
  template:`<div>{{n}}</div>`
}).$mount("#app");

console.log(amout); // {__ob__:Observer}
Copy the code

Both of these output values are strange. The first one is an object, but when I open the object, I see this:



I find that I can’t explain this phenomenon. Why do the values I pass in change? So I started to look for information, and finally I came to the conclusion that vUE changed the value of my object when I passed in this value, and passed the changed value to the address value of my object. How does it do that? Why would you do that? Start by explaining why you’re doing it.

Why is that?

The answer is simple, because vUE needs to listen for changes in the data and render the changes to the page from time to time, which is to achieve vUE data responsive functionality.

How did you do that?

DefineProperty is an Object method that can be used to operate on a value of an Object. For example, IF I want to assign c to the b attribute of Object A, it looks like this:

const a = {b:"b"};
Object.defineProperty(a,"b",{
  value:"c"
})
Copy the code

After wrapping the object and typing object a again, I get my first value, which is n:(…). “, so it’s clear that Vue has been packaged this way. So the question is, what is this packaging for? So we’re trying to do getter,setter encapsulation of b in an OBJECT that we did a while ago

Const A._b = "b" // Use a _b to store the value of b object.defineProperty (a,"b",{get(){return A._b}, Set (value){fn// tell vue I have been modified return A._b = value}})Copy the code

Calling a.b now yields the value stored in _B. Using setter methods, we successfully listen for the data. However, the problem still exists. In this case, the user can change the value of _B externally. This is equivalent to b being changed, which also causes the value of B to be wrong. How to do? So encapsulation again, introducing the concept of proxy.

const a = proxy({data:{b:0}}); function proxy({... data}){ const obj = {}; Object.defineProperty(obj,"b",{ get(){ return data.b }, Set (value){fn// tell vue I have been modified return data.b = value}}) return obj}Copy the code

In short, it’s a function that wraps up what’s being passed in, and then tells me to change the value of the opposite, and the outside can’t change the value of itself. But the problem is that if I change the value passed through the proxy, it still succeeds. And then you have to listen again for the values that come in from the outside, and at this point, it’s perfect.

function proxy2({... data}){ let value = data.b Object.defineProperty(data, 'b', { get(){ return value }, Set (newValue){fn// tell vue I was modified value = newValue}}) const obj = {} object.defineProperty (obj, 'b', {get(){return data.n}, set(value){fn// tell vue I am modified data.n = value}}) return obj}Copy the code

At this point, it should be a perfect reproduction of the essence of what VUE does, which is the root cause of its amazing responsiveness to listen to data.

conclusion

When you pass an ordinary JavaScript object into a Vue instance as the data option, Vue iterates through all of the object’s properties, We use Object.defineProperty to convert all of these properties into getters/setters so that Vue can proxy these objects. Object.defineproperty, these getters/setters are not visible to the user, but internally because of Vue’s proxy, Vue can listen for changes to the Object and re-render the entire page, thus making it responsive.