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

相关推荐
YBN娜5 分钟前
Vue实现登录功能
前端·javascript·vue.js
阳光开朗大男孩 = ̄ω ̄=5 分钟前
CSS——选择器、PxCook软件、盒子模型
前端·javascript·css
minDuck9 分钟前
ruoyi-vue集成tianai-captcha验证码
java·前端·vue.js
小政爱学习!30 分钟前
封装axios、环境变量、api解耦、解决跨域、全局组件注入
开发语言·前端·javascript
魏大帅。35 分钟前
Axios 的 responseType 属性详解及 Blob 与 ArrayBuffer 解析
前端·javascript·ajax
花花鱼41 分钟前
vue3 基于element-plus进行的一个可拖动改变导航与内容区域大小的简单方法
前端·javascript·elementui
k09331 小时前
sourceTree回滚版本到某次提交
开发语言·前端·javascript
EricWang13581 小时前
[OS] 项目三-2-proc.c: exit(int status)
服务器·c语言·前端
September_ning1 小时前
React.lazy() 懒加载
前端·react.js·前端框架
web行路人1 小时前
React中类组件和函数组件的理解和区别
前端·javascript·react.js·前端框架