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源码的博大精深,也还是挺好的

相关推荐
无限大.5 小时前
前端知识速记:节流与防抖
前端
十八朵郁金香5 小时前
【VUE案例练习】前端vue2+element-ui,后端nodo+express实现‘‘文件上传/删除‘‘功能
前端·javascript·vue.js
学问小小谢5 小时前
第26节课:内容安全策略(CSP)—构建安全网页的防御盾
运维·服务器·前端·网络·学习·安全
LCG元6 小时前
Vue.js组件开发-实现全屏图片文字缩放切换特效
前端·javascript·vue.js
还是鼠鼠7 小时前
图书管理系统 Axios 源码__新增图书
前端·javascript·vscode·ajax·前端框架·node.js·bootstrap
还是鼠鼠10 小时前
图书管理系统 Axios 源码 __删除图书功能
前端·javascript·vscode·ajax·前端框架·node.js·bootstrap
轻口味10 小时前
Vue.js `Suspense` 和异步组件加载
前端·javascript·vue.js
m0_zj11 小时前
8.[前端开发-CSS]Day08-图形-字体-字体图标-元素定位
前端·css
还是鼠鼠11 小时前
图书管理系统 Axios 源码__编辑图书
前端·javascript·vscode·ajax·前端框架
北极象11 小时前
vue3中el-input无法获得焦点的问题
前端·javascript·vue.js