Vue的methods里面的this为什么会指向Vue实例?

Posted 天地会珠海分舵

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Vue的methods里面的this为什么会指向Vue实例?相关的知识,希望对你有一定的参考价值。

相信我们写Vue代码时肯定都会在methods中用过this这个关键字,甚至还打印过this查看其内容。最终发现该实例对象竟然是我们的Vue实例对象。

如果是组件的话,将会是VueComponent实例对象,Vue和VueComponent两个类其实差不都,今后会另外开章节描述两者差别,这里先飘过。

比如下面的简单的一个demo代码,点击按钮打印出this。

<!DOCTYPE html>
<html lang="en">
  <head>
    <script src="../../dist/vue.js"></script>
  </head>
  <body>
    <div id="app">
      <button @click="printThis">What is this</button>
    </div>

    <script>
      const vm = new Vue(
        el: "#app",
        data: 
          counter: 0,
        ,
        methods: 
          printThis() 
            console.log("this:", this);
          ,
        ,
      );
    </script>
  </body>
</html>

最终打印的结果将会如下:


很明显,vue框架通过某种方法自动帮我们将methods下面的this指向到vue的实例对象了。

下面跟踪下vue的源代码,看下是怎么实现的。

首先,我们看下new Vue的入口,也即是Vue类的构造函数

function Vue(options) 
  ...
  this._init(options);

构造函数的参数options就是我们前面new Vue时传入的带有methods和data这些配置项的对象。

构造函数里面会做很多初始化的动作,这些动作都被封装到_init这个方法中了。因为是通过this调用的,所以我们可以猜想到这个方法应该是写到了Vue的prototype上的。

Vue.prototype._init = function (options?: Object) 
    const vm: Component = this;
    ...
    // 将含有methods和data等配置项的对象合并并挂到Vue实例对象vm的$options属性上
    if (options && options._isComponent) 
      // optimize internal component instantiation
      // since dynamic options merging is pretty slow, and none of the
      // internal component options needs special treatment.
      initInternalComponent(vm, options);
     else 
      vm.$options = mergeOptions(
        resolveConstructorOptions(vm.constructor),
        options || ,
        vm
      );
    ...
    initState(vm);
    ...
  ;

该方法会将我们new Vue时提供的带有methods和data的配置项放入到Vue实例对象的$options属性中,然后调用initState方法。


export function initState(vm: Component) 
  ...
  if (vm.$options.methods) initMethods(vm, vm.$options.methods);
  ...

因为我们提供了methods选项,记得吧?我们上面methods写了printThis方法。所以这里会调用到initMethods方法,传入的参数是Vue实例对象vm和我们传进来的methods选项。

function initMethods(vm: Component, methods: Object) 
  ...
  for (const key in methods) 
    ...
    vm[key] =
      typeof methods[key] !== "function" ? noop : bind(methods[key], vm);
  

上面的代码逻辑主要就是循环methods里面的每个方法,然后将这些方法以相同的名字在vue实例对象中也放一份,比如我们的printThis方法,在vue实例对象中也来一份。


但是放到vue实例对象中的这些方法和原来的有一些区别,什么区别呢?就是通过上面的bind方法做了些调整。

这个bind方法看上去是不是很眼熟,名字和我们javascript用来修改this指向的bind方法一样。

而事实上这个bind方法最终调用的是一个叫做nativeBind的方法

function nativeBind (fn: Function, ctx: Object): Function 
  return fn.bind(ctx)

该方法做的事情就是将我们传入来的method,即我们这里的printThis方法的this的指向,指向到了传进来的vm,即我们的vue实例对象。

而这,也即是为什么我们在methods里面的方法可以通过this直接访问到Vue实例对象的原因了。

我是@天地会珠海分舵,「青葱日历」和「三日清单」作者。能力一般,水平有限,觉得我说的还有那么点道理的不妨点个赞关注下!

以上是关于Vue的methods里面的this为什么会指向Vue实例?的主要内容,如果未能解决你的问题,请参考以下文章

vue这里的this指向哪里

vue的methods中方法2中调用this.方法1

vue中computed计算属性与methods对象中的this指针

vue中子组件的methods中获取到props中的值方法

VUE 定义的this 为啥在JS里面会变

vue-element的表单验证能调用methods里的方法吗?