new Vue() 时做了什么

本文探讨了Vue构造函数的内部工作原理,特别是new Vue()时发生的关键步骤。在实例化过程中,Vue执行了初始化操作,包括将options中的属性挂载到实例上,并使用proxy方法将data属性代理到_data对象。通过分析,我们可以理解Vue如何在实例的生命周期中处理用户定义的钩子函数和数据。

new Vue() 时做了什么


import Vue from 'vue'

var app = new Vue({
    el: '#app',
    mounted() {
        console.log(this.message) //hello
    },
    data() {
        return {
            message: 'hello'
        }
    }
})

这块代码我们很熟悉,引用vue,然后创建Vue实例,那我们有没有想过我们在data中定义的key是如何挂载到实例上的,比如我们在mounted的钩子函数中是如何通过this.message获取到我们定义的值。

通过分析这部分代码,我想向大家分享阅读源码的心得:最好有一个明确的目的,例如分析data的挂载,然后在分析的过程中可以暂时跳过一些不相关的代码,没必要一下子深扒所有代码。


src/core/instance/index.js

function Vue (options) {
    ...
    this._init(options)
}

initMixin(Vue)

首先从instance目录的入口开始,我们看到了Vue的构造函数,在构造函数中看到vue在实例化时执行了_init方法,而这个方法则是通过调用initMixin方法将_init方法定义在Vue的原型上。

src/core/instance/init.js

export function initMixin (Vue: Class<Component>) {
    Vue.prototype._init = function (options?: Object) {
        ...
        vm._self = vm
        initLifecycle(vm)
        initEvents(vm)
        initRender(vm)
        callHook(vm, 'beforeCreate')
        initInjections(vm)
        initState(vm) //@1
        initProvide(vm)
        callHook(vm, 'created')
        ...
    }
}

@1:

_init方法中主要做了一些初始化的操作,这里我们先略过方法中的其他代码,主要看 initState(vm) 做了什么,它跟挂载data相关。

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) //@1
  } else {
    observe(vm._data = {}, true /* asRootData */)
  }
  if (opts.computed) initComputed(vm, opts.computed)
  if (opts.watch && opts.watch !== nativeWatch) {
    initWatch(vm, opts.watch)
  }
}

@1:

initState方法中主要是将options中的data, props, methods等挂载到vm实例上,这里我们看一下initData(vm)的代码:

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) //@1
    }
  }
  // observe data
  observe(data, true /* asRootData */)
}

@1:

核心代码就是

proxy(vm, `_data`, key)

vue通过proxy方法将key代理到vm的_data上,我们看详细的代码实现:

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) //@1
}

参数target就是传入的vm实例,sourceKey就是代理的key:_datakey则是我们要访问的键。

@1:

定义实例对象的属性描述,添加了getset方法,当我们访问this.key的时候,实际上是返回了this._data.key,我们可以在一开始的代码中打印this._data.message,也可以返回相同的内容。

`new Vue` 是用于创建一个 Vue 实例的关键语法。通过这个实例,你可以初始化和管理基于 Vue.js 框架的应用程序或组件。下面是对它的详细解析: ### 1. 基本形式 ```javascript new Vue({ // 配置选项 }) ``` 当你执行 `new Vue({...})` Vue 会依据传入的对象配置生成一个新的应用实例,并将指定的模板挂载到页面上。 --- ### 2. 主要配置项解释 - **el**: - 类型:字符串 (CSS选择器) - 功能:绑定 DOM 元素作为 Vue 应用的作用域区域。例如,`el: '#app'` 表明此 Vue 实例将会接管 HTML 页面中 ID 为 app 的 div 区块。 - **data**: - 类型:对象 | 函数(当在一个组件内使用) - 功能:包含所有需要被响应的数据属性。如: ```javascript data() { return { message: 'Hello World' } } ``` - **methods**: - 类型:对象 - 功能:定义一些可以在事件触发或其他地方调用的方法函数。比如点击按钮改变文本可以这么写: ```javascript methods:{ changeMessage(){ this.message = "Changed Message"; } } ``` - **computed**: - 类型:对象 - 功能:计算属性,基于已有数据动态派生新值并且自动缓存更新后的状态除非关联依赖发生变动。相比于普通 method 来说更高效简洁。 - **watch**: - 类型:对象 - 功能:监听特定数据的变化然后出反应,允许开发者添加副作用操作等复杂逻辑。 --- ### 简单示例 假设有一个简单的网页想要打印消息以及修改该消息的功能,则可以用如下代码实现: ```html <div id="example"> {{ message }} <button @click="reverseMessage">反转消息</button> </div> <script src="https://cdn.jsdelivr.net/npm/vue@2"></script> <script> var vm = new Vue({ el: '#example', data: function () { return {message:"原始信息"} }, methods:{ reverseMessage:function(){ var words=this.message.split(''); this.message=words.reverse().join(''); } } }); </script> ``` 这里我们先引入了官方提供的 CDN 版本库文件加载完毕后再编写脚本来完成交互需求。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值