最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • Vue.js源码学习——Vue对象在data中定义的属性为什么可以直接通过this.xxx访问?

    正文概述 掘金(小馒头儿)   2021-02-01   515

    我们在Vue对象中可以通过this.xxx去访问Vue中data对象中定义的数据,但是为什么可以直接使用this.xxx来访问呢?我们可以用过看源码的方式来进行理解。

    当我们使用new的方式创建一个Vue实例的时候,实际上调用的是一个Vue的方法。

    /* src/core/instance/index.js */
    function Vue (options) {
      if (process.env.NODE_ENV !== 'production' &&
        !(this instanceof Vue)
      ) {
        warn('Vue is a constructor and should be called with the `new` keyword')
      }
      this._init(options)
    } 
    

    初始化的时候,Vue方法中主要调用了_init这个方法。

    这个_init方法实际上是一个挂在在Vue原型上的一个方法。同样在这个文件中含有一行代码initMixin(Vue)就是完成了挂载_init方法在Vue原型上的一个操作。

    然后我们进入_init(options)来看进行了哪些操作。这个时候进入src/core/instance/init.js找到initMixin方法。

    initMixin一开始就可以看到Vue.prototype._init = function() {} 这个就是Vue对象原型上的_init方法了。然后来看这个方法中进行了哪些操作?这个时候忽略一些细节,直接看到有一段全是initXXX的函数调用。这一块大致就是Vue对象初始化的一些流程,比如生命周期,事件等等。

    /* src/core/instance/init.js */
    export function initMixin (Vue: Class<Component>) {
      Vue.prototype._init = function (options?: Object) {
        /* more details */
        vm._self = vm
        initLifecycle(vm)
        initEvents(vm)
        initRender(vm)
        callHook(vm, 'beforeCreate')
        initInjections(vm) // resolve injections before data/props
        initState(vm)
        initProvide(vm) // resolve provide after data/props
        callHook(vm, 'created')
        /* more details */
        }
    } 
    

    关于data的处理就聚焦在这个initState方法上。initState这个方法是引入到这个文件的,所以我们找到initState这个方法真正定义的地方src/core/instance/state.js

    initState定义的结构看起来很简单,就是根据我们的options上的不同属性来做相应的初始化处理。

    /* src/core/instance/state.js */
    export function initState (vm: Component) {
      vm._watchers = []
      const opts = vm.$options
      if (opts.props) initProps(vm, opts.props)
      if (opts.methods) initMethods(vm, opts.methods)
      if (opts.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)
      }
    } 
    

    我们的主要目标还是data,这个时候我们我们就主要去看data属性下进行的操作。data选项存在时候就调用了initData,不存在的时候就调用了observer,同时把data用一个空对象赋值。observer和数据响应式相关,这里先不详细说明。

    接下来就是去看initData做了什么处理了?

    /* src/core/instance/state.js */
    function initData (vm: Component) {
      let data = vm.$options.data
      data = vm._data = typeof data === 'function'
        ? getData(data, vm)
        : data || {}
      if (!isPlainObject(data)) {
        data = {}
        process.env.NODE_ENV !== 'production' && 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
      const keys = Object.keys(data)
      const props = vm.$options.props
      const methods = vm.$options.methods
      let i = keys.length
      while (i--) {
        const key = keys[i]
        if (process.env.NODE_ENV !== 'production') {
          if (methods && hasOwn(methods, key)) {
            warn(
              `Method "${key}" has already been defined as a data property.`,
              vm
            )
          }
        }
        if (props && hasOwn(props, key)) {
          process.env.NODE_ENV !== 'production' && 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)
        }
      }
      // observe data
      observe(data, true /* asRootData */)
    } 
    

    initData的操作分为三个部分:

    • 判断data是否是一个函数
    • 数据代理
    • 响应式(暂不详细说明)
    1. 我们在创建一个新的Vue对象的时候,data是一个函数,返回一个含有定义参数的新对象,如果不是一个函数,就会进行报错。具体原因和组件相关。

      new Vue({
        data() {
         return {
            message: 'Hello world',
         }
        },
      });
          
      new Vue({
        data: {
          message: 'Hello world',
      	},
      }); 
      
    2. 数据代理的时候要确保data中的属性名称不能和propsmethod和保留属性不能重名,因为最后这些都会挂载在Vue的实例上。代理的实现部分依赖proxy这个方法。

      /* src/core/instance/state.js */
      export function proxy (target: Object, sourceKey: string, key: string) {
        sharedPropertyDefinition.get = function proxyGetter () {
          return this[sourceKey][key]
        }
        sharedPropertyDefinition.set = function proxySetter (val) {
          this[sourceKey][key] = val
        }
        Object.defineProperty(target, key, sharedPropertyDefinition)
      } 
      

      通过设置一个对象上的访问器属性getset,就能使我们在访问vm.xxx的时候去访问vm._data.xxx了。vm_data属性则是在initData中判断data是否使一个函数的时候的赋值操作。这样当我们去访问vm.xxx实质上就是访问的我们定义的data上的属性了。


    起源地下载网 » Vue.js源码学习——Vue对象在data中定义的属性为什么可以直接通过this.xxx访问?

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元