为什么将vue实例的_data对象代理到vue原型链上,而不代理到实例对象上

vue源码如下(来自文件src/core/instance/index):

  // src/core/instance/index
  const dataDef = {}
  dataDef.get = function () { return this._data }
  const propsDef = {}
  propsDef.get = function () { return this._props }
  if (process.env.NODE_ENV !== 'production') {
    dataDef.set = function () {
      warn(
        'Avoid replacing instance root $data. ' +
        'Use nested data properties instead.',
        this
      )
    }
    propsDef.set = function () {
      warn(`$props is readonly.`, this)
    }
  }
  Object.defineProperty(Vue.prototype, '$data', dataDef)
  Object.defineProperty(Vue.prototype, '$props', propsDef)

从这段代码来看,是将实例的_data对象进行代理,以遍可以直接用$data进行取值
那么为什么要将$data定义在vue的原型对象上,而不是实例上

阅读 5.4k
3 个回答

没有深入研究。以下言论或许有误:
$data属性是在new Vue之前就已经定义好的

// src/core/instance/index
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)
}

initMixin(Vue)
stateMixin(Vue)
eventsMixin(Vue)
lifecycleMixin(Vue)
renderMixin(Vue)
// src/core/instance/state
Object.defineProperty(Vue.prototype, '$data', dataDef)

$data是在stateMixin函数中初始化的,而stateMixin是在Vue是初始化过程中调用的,在new之前,如果要把$data定义在实例上则需要在new Vue的时候去初始化,而其实并不需要这么麻烦,只要再原型上代理既可以,因为$data被定义为一个getter,实际上它仍然访问的是this._data。所以可以比较早的先初始化好这个getter。而且,这里Vue是用Object.defineProperty去初始化的,而这个有一个好处就是——实例上也有会这个属性.
举个例子

function fn() {
    this._init()
}
fn.prototype._init = function() {}
Object.defineProperty(fn.prototype, '$data', {get() {return '$data'}})
console.log(new fn())

豆芽图片20200103195701.png
虽然属性定义在原型上,但是实例也是有的。

新手上路,请多包涵

为什么要将$data定义在vue的原型对象上,而不是实例上???

$data 定义在原型译为只读属性,扒了下vue源码,实例上的_data是可读写的,注意 $,_,原型固有属性的开头使用$开头, 实例属性则使用_开头, 两种模式都可以读取到data

问这个问题之前,先说明清楚你的目的是什么,不然毫无意义,

为什么要代理到实例上? 有什么好处?达到什么效果?

如果没有这几个问题,对方说什么,你都会来一句,为什么不可以?

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题