Vue 的 data 函数里的 this 用法

本文深入解析Vue实例的创建过程,详细阐述props与data的初始化顺序,以及如何实现数据的响应式。在Vue中,data函数被调用时传入当前Vue实例,props在data之前初始化,因此在data中可以访问到props的值。然而,data正在初始化时,其内部的属性尚未被代理到Vue实例上,故无法直接访问。同时,文章还探讨了在方法中this的指向问题。
摘要由CSDN通过智能技术生成

代码示例

const app = new Vue({
  el: '#app',
  props: {
    id: {
      type: String,
      default: '10000'
    }
  },
  data(vm) {
    console.log('data', this) // ==> #1. 当前 Vue 实例
    console.log('data', vm) // ==> #2. 当前 Vue 实例
    return {
      newId: '10086',
      myId1: this.id, // ==> #3. myId1 等于 10000
      myId2: this.newId, // ==> #4. myId2 等于 undefined
      regFunc() {
        console.log(this) // ==> #5. 当前 Vue 实例
      },
      arrowFunc:() => {
        console.log(this) // ==> #6. 当前 Vue 实例
      }
    }
  },
  created() {
    console.log('this.$data', this.$data)
    this.regFunc()
    this.arrowFunc()
  },
  methods: {
  }
})

解析:#1 和 #2

#1 和 #2 都为当前 Vue 实例,因为 Vue 通过 data.call(vm, vm) 调用 data 函数

源码参考:getData

function getData (data, vm) {
  // #7573 disable dep collection when invoking data getters
  pushTarget();
  try {
    return data.call(vm, vm) // ==> 调用 data 函数
  } catch (e) {
    handleError(e, vm, "data()");
    return {}
  } finally {
    popTarget();
  }
}

解析: #3

#3 等于 10000,因为 Vue 在初始化 data 前已经初始化完 props。所以 this.id = 10000,即 this.myId1 = 10000。这里的初始化指的是对 id 属性进行取值,将 id 属性代理到 Vue 示例对象上,并做响应式监听

源码参考:initState

function initState (vm) {
   vm._watchers = [];
   var opts = vm.$options;
   if (opts.props) { initProps(vm, opts.props); } // ==> 先初始化 props
   if (opts.methods) { initMethods(vm, opts.methods); }
   if (opts.data) { // ==> 再初始化 data
     initData(vm);
   } else {
     observe(vm._data = {}, true /* asRootData */);
   }
   if (opts.computed) { initComputed(vm, opts.computed); }
   if (opts.watch && opts.watch !== nativeWatch) {
     initWatch(vm, opts.watch);
   }
 }

解析: #4

#4 等于 undefined,因为此时的 data 初始化正在进行,即在取值步骤(参考上面初始化的解释),还未进行代理和监听(此时 newId 未代理到 this 上),所以 this.newId 等于 undefined

源码参考:initData

function initData (vm) {
   var data = vm.$options.data;
   data = vm._data = typeof data === 'function'
     ? getData(data, vm) // ==> 1. 取值
     : data || {};
   if (!isPlainObject(data)) {
     data = {};
     warn(
       'data functions should return an object:\n' +
       'https://vuejs.org/v2/guide/components.html#data-Must-Be-a-Function',
       vm
     );
   }
   // proxy data on instance
   var keys = Object.keys(data);
   var props = vm.$options.props;
   var methods = vm.$options.methods;
   var i = keys.length;
   while (i--) {
     var key = keys[i];
     {
       if (methods && hasOwn(methods, key)) {
         warn(
           ("Method \"" + key + "\" has already been defined as a data property."),
           vm
         );
       }
     }
     if (props && hasOwn(props, key)) {
       warn(
         "The data property \"" + key + "\" is already declared as a prop. " +
         "Use prop default value instead.",
         vm
       );
     } else if (!isReserved(key)) {
       proxy(vm, "_data", key); // ==> 2. 代理到 vm 上
     }
   }
   // observe data
   observe(data, true /* asRootData */); // ==> 3. 做响应式监听
 }
  • 8
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值