Vue.js中data的代理

主要背景

因为对Vue.js很感兴趣,而且工作中用到的技术栈也是它,所以停留在api调用工程师肯定不行,所以就去看了看源码,研究其中的实现内容。

如果有任何问题,还请各位大佬不吝赐教

从vue2项目说起

js 复制代码
export default {
    data(){
        return {
            a:1,
            b:2,
        }
    }
}

在我们的项目中,访问this.a或者this.data.a都可以,那么问题来了,a明明是data函数中的对象,为什么this.a可以访问到。为此去看了Vue.js的源码。

首先,Vue.js初始化即我们new Vue()时候,做了一件事情

js 复制代码
function Vue(options) {
  if (__DEV__ && !(this instanceof Vue)) {
    warn('Vue is a constructor and should be called with the `new` keyword')
  }
  this._init(options)
}

上面的options就是我们实例化的时候传入的对象,比如

js 复制代码
new Vue({
  router,
  store,
  render: (h) => h(App),
}).$mount("#app");

options = {
  router,
  store,
  render: (h) => h(App),
}

_init函数定义在src/core/instance/init.ts,做了很多事情,比如:初始化生命周期、事件、props、data等,

src/core/instance/state.ts就是初始化props、data的文件,方法名:initState,此处拿initData说明

js 复制代码
function initData(vm: Component) {
  let data: any = vm.$options.data
  data = vm._data = isFunction(data) ? getData(data, vm) : data || {}
  if (!isPlainObject(data)) {
    data = {}
    __DEV__ &&
      warn(
        'data functions should return an object:\n' +
          'https://v2.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 (__DEV__) {
      if (methods && hasOwn(methods, key)) {
        warn(`Method "${key}" has already been defined as a data property.`, vm)
      }
    }
    if (props && hasOwn(props, key)) {
      __DEV__ &&
        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
  const ob = observe(data)
  ob && ob.vmCount++
}

上述函数主要做了三件事情

  1. data中定义的key不能和props/methods中相同
  2. 进行代理,即proxy函数
  3. 对data进行数据绑定,即observe函数

proxy函数

代码如下

js 复制代码
const sharedPropertyDefinition = {
  enumerable: true,
  configurable: true,
  get: noop,
  set: noop
}

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)
}

target = Vue对象,sourceKey = data,key = data中各属性

通过Object.defineProperty(target, key, sharedPropertyDefinition)函数定义后续通过this.xx访问data中的属性时,代理到this[data][xx]中,即this.xx访问时底层还是通过this.data.xx来实现的。

最后

如此恍然大悟,以前是只知道用,结果出来就可以了,现在去看看源码,感受Vue源码的博大精深,也还是挺好的

相关推荐
Highcharts8 分钟前
用Highcharts如何动态向一个序列添加点-示列讲解
前端
weixin_4316004419 分钟前
做 Agent 会用到的 Node API(4):取消与 AbortController
前端·学习·ai·agent·ai编程
用户21816970493032 分钟前
Flutter(十)Container Center Align
前端
无人生还41 分钟前
从 Vue3 到 React · 快速上手系列第 12 篇:并发特性与性能优化
前端·vue.js·react.js
小p43 分钟前
nextjs学习9: Next.js 渲染与缓存
前端·后端
乘风gg43 分钟前
AI 时代,你的编程能力在第几层?我敢说,大多数人卡在第一层
前端·ai编程·claude
东风破_44 分钟前
React Router v7 实战:用路由配置、懒加载与嵌套路由搭建一个完整的 SPA
前端
引山洪081 小时前
Babylon.js 8.x 中文文档整理——Node篇 (上)
前端·webgl
柒和远方1 小时前
V058:前端路由的第一性原理:从 hashchange 手写路由,到 React Router 的嵌套与懒加载
前端·javascript·react.js
计算机魔术师1 小时前
阿里云上线 One Key MCP 服务:兼容 Qoder、Codex 等,可一键调用多家 MCP 服务
前端