SoFunction
Updated on 2025-03-08

Why can Vue2 access the properties of data and methods through this

Preface

Before I got into vue, I had never touched on what this is. After I learned vue, I knew this. At that time, I understood this, which means that you should use properties in data or call methods in methods, etc., and I had to use this to call it. At that time, I actually didn't know what this was. I later learned that it should be memorized by eight-legged essays. By reading this source code today, I understood it more deeply. It turned out that it could be used like this.

1. Use of vue

Looking at this code, we can know that there is a Vue constructor. Then we use new Vue to create its instance and pass an object parameter to it, which contains data and methods. So what does this Vue constructor do to allow me to directly access the properties or methods in it using this?

    //Create an instance of vue    const vm = new Vue({
        data: {
            desc: 'Why can this directly access properties in data',
        },
        methods: {
            sayName() {
                ();
            }
        },
    });
    ();
    (());

2. Vue constructor

Receive an option parameter

  • Use instanceof to determine whether Vue's prototype appears on this object. We all know that the direction of this depends on who calls it
  • This._init(options) proves that in this call, either the instance we created has a _init method or the method is on the Vue prototype, but we can see that there is no _init method on the instance, so we must add a _init method to the Vue prototype in one place. Continue to read
 function Vue(options) {
        if (!(this instanceof Vue)
        ) {
            warn('Vue is a constructor and should be called with the "new" keyword');
        }
        this._init(options);
}
//Vue() //The wrong way to call Enter warning judgment at this timethisPoint towindow Thenwindowof window.__proto__ofPoint toofWindow构造函数ofprototype

3. Initialize initMixin(Vue)

In the source code, you will see many initialized functions. Here we are initMixin()

This function adds the _init method to the Vue prototype. The method receives a parameter and then defines the vm variable. When I look at it, I want to see who this function points to. In fact, it is not difficult for the function to hang on the Vue constructor prototype. The call is still called in the constructor. This constructor points to the Vue instance, and according to this pointing rules, the vm points to the Vue constructor instance.

If the access rules are not on the instance, go to the prototype to find it

Then execute initState(vm)

initMixin(Vue)
function initMixin(Vue) {
        // Add init method on prototype        ._init = function (options) {
            var vm = this; //Vue instance          	 = 30
          //The code has been deleted            initState(vm);
        }
}
// Here is just an example testconst vm = new Vue({})
() //30

Four initState(vm)

Here we perform different processing on the data or methods we pass in

 //The initState method code has been deleted    function initState(vm) {
        vm._watchers = [];
        var opts = vm.$options; //This is the parameter we pass when creating an instance        //If methods are passed, go to call        if () { initMethods(vm, ); }
        if () {
            initData(vm);
        } else {
            observe(vm._data = {}, true /* asRootData */);
        }
    }

Five initMethods(vm, )

If there are methods, call the initMethods method

The previous one is mainly to determine whether the value in methods is a function, whether the key conflicts with props, etc.

The last piece of code is to add the method vm[key]=methods[key] to the vm instance. When I read it, I have a question like this thinking why I still use bind to change this pointing? Isn’t it originally written on the vm instance? I can only use vm to call. So doesn’t this method point to vm?

/*
     vm:Constructor instance
     methods: the methods object we pass
     */
    function initMethods(vm, methods) {
        var props = vm.$;
        //Loop methods object        for (var key in methods) {
            {
                //Judge whether it is a function. If it is not, a warning will be given.                if (typeof methods[key] !== 'function') {
                    warn(
                        "Method "" + key + "" has type "" + (typeof methods[key]) + "" in the component definition. " +
                        "Did you reference the function correctly?",
                        vm
                    );
                }
                //Judge whether each item in methods conflicts with props. If so, a warning.                if (props && hasOwn(props, key)) {
                    warn(
                        ("Method "" + key + "" has already been defined as a prop."),
                        vm
                    );
                }
                //Judge whether each item in methods already exists on the new Vue instance vm, and the method name is reserved _$ (usually refers to the internal variable identifier in JS), if it is a warning.                if ((key in vm) && isReserved(key)) {
                    warn(
                        "Method "" + key + "" conflicts with an existing Vue instance method. " +
                        "Avoid defining component methods that start with _ or $."
                    );
                }
            }
            //Add methods in methods to the instance, so we can actually use vm to access methods in methods            vm[key] = typeof methods[key] !== 'function' ? noop : bind(methods[key], vm);
        }
    }

After asking the big guys in the group, I found out that in order to prevent the user from changing this direction, I made an example.

Here I have defined an age attribute and fn in object a. I assign fn to sayHi on the vm instance, and then the () call is obviously the pointing of this has been changed, and after using bind it will not

  const vm = new Vue({
        methods: {
            sayHi() {
                (, 'hello-this')
            }
        }
    });
    let a = {
        age: 15,
        fn: 
    }
    ((), 'vm') //Print15

Six initData(vm)

How data can be directly accessed using this, but the principles are the same.

First, add _data to the vm instance, and the data parameters we passed in are stored in it.

 function initData(vm) {
        var data = vm.$;
        data = vm._data = typeof data === 'function'
            ? getData(data, vm)
            : data || {};
        //Warning if it is not an object        if (!isPlainObject(data)) {
            data = {};
            warn(
                'data functions should return an object:\n' +
                '/v2/guide/#data-Must-Be-a-Function',
                vm
            );
        }
        // proxy data on instance
        var keys = (data);
        var props = vm.$;
        var methods = vm.$;
        var i = ;
        while (i--) {
            var key = keys[i];
            //Judge whether the key value has a duplicate name with the key in methods            {
                if (methods && hasOwn(methods, key)) {
                    warn(
                        ("Method "" + key + "" has already been defined as a data property."),
                        vm
                    );
                }
            }
            //Judge whether the key value has a duplicate name with the key in props            if (props && hasOwn(props, key)) {
                warn(
                    "The data property "" + key + "" is already declared as a prop. " +
                    "Use prop default value instead.",
                    vm
                );
                //Is it the strings $ and _ reserved internally, which begin with private strings            } else if (!isReserved(key)) {
              //acting                proxy(vm, "_data", key);
            }
        }
        // observe data
        observe(data, true /* asRootData */);
    }

7 proxy(vm, "_data", key)

get and set methods Note that this inside points to the vm instance object, and _data has been added to the vm instance object. All when obtaining or setting attribute values ​​is this._data[key], that is, vm._data[key],

Then add attributes to the instance object, so when we access vm[key], that is, vm._data[key]

  function proxy (target, sourceKey, key) {
       = function proxyGetter () {
        return this[sourceKey][key]
      };
       = function proxySetter (val) {
        this[sourceKey][key] = val;
      };
      (target, key, sharedPropertyDefinition);
  }
//Create a vue constructor    function Vue(options) {
        if (!(this instanceof Vue)
        ) {
            warn('Vue is a constructor and should be called with the "new" keyword');
        }
        this._init(options);
    }
    //initialization    initMixin(Vue);
    function initMixin(Vue) {
        // Add init method on prototype        ._init = function (options) {
            var vm = this; //Vue instance            let methods = 
            initState(vm);
        }
    }
    //The initState method code has been deleted    function initState(vm) {
        vm._watchers = [];
        var opts = vm.$options; //This is the parameter we pass when creating an instance        //If methods are passed, go to call        if () { initMethods(vm, ); }
        if () {
            initData(vm);
        } else {
            observe(vm._data = {}, true /* asRootData */);
        }
    }
    /*
     vm:Constructor instance
     methods: the methods object we pass
     */
    function initMethods(vm, methods) {
        var props = vm.$;
        //Loop methods object        for (var key in methods) {
            {
                //Some conditions to judge            }
            //Add methods in methods to the instance, so we can actually use vm to access methods in methods            vm[key] = typeof methods[key] !== 'function' ? noop : bind(methods[key], vm);
        }
    }
    const vm = new Vue({
        methods: {
            sayHi() {
                ('hello-this')
            }
        }
    });
    () //hello-this

Summarize

In fact, I understand how Methods can be directly accessed with this. The following are similar. It mainly consists of a constructor, and then create an instance, adding properties or methods to the instance, so that we can access it directly using the instance object. The principle is that simple.

This is the article about why Vue2 can access the properties of data and methods through this. For more information about Vue2 accessing data, please search for my previous articles or continue browsing the related articles below. I hope everyone will support me in the future!