• 简单理解Vue的data为啥只能是函数


    前言

    在学习vue的时候vue2只有在组件中严格要求data必须是一个函数,而在普通vue实例中,data可以是一个对象,但是在vue3出现后data必须一个函数,当时看着官方文档说的是好像是对象的引用问题,但是内部原理却不是很了解,今天通过一个简单的例子来说明为啥data必须是一个函数

    1.Vue3中的data

    const { createApp } = Vue
    const app = {data: {a: 1},template: `

    {{a}}

    ` } createApp(app).mount('#app')
    • 1
    • 2
    • 3
    • 4

    2.vue中的data

    var app = new Vue({el: '#app',data: { a: 'hello world' }
    }) 
    
    • 1
    • 2

    这种写法是可以的,前面提过普通实例data可以是对象,但是在组件中必须是函数, **那么在vue2中难道普通实例就没有缺陷嘛?**答案:是有缺陷的, 比如这样

    {{ message }}
    {{ message }}
    • 1
    • 2
     const data = { message: 'hello world' }
    const vue1 = new Vue({el: '#app1',data
    })
    
    const vue2 = new Vue({el: '#app2',data
    }) 
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    这样在页面中会显示2个内容为hello world的div标签 那么当我们通过实例去改变messag呢?

     vue1.message = 'hello Vue' 
    
    • 1

    奇怪的事情发生了,我知识改变了vue1的实例中的数据,但是其他实例的数据也发生了改变,相信很简单就能看出来这应该是共用同一个对象的引用而导致的,这在开放中是非常不友好的,开发者很容易就产生连串的错误,vue2也知道这种缺陷只是没有在普通实例中去体现而已,只在组件中实现了对于data的约束

    为了让大家更好的立即为啥data必须是一个函数,黑猫在此简单实现一个vue的实例然后来证明为啥data是一个函数,以及如果data不是一个函数,我们应该如何处理

    3.证明data是函数以及原理实现

    在实现简单原理之前,我们需要搞清楚Vue在创建实例之前,对于data到底做了什么事情简单来说就是:

    vue 在创建实例的过程中调用data函数返回实例对象通过响应式包装后存储在实例的data上并且实例可以直接越过data上并且实例可以直接越过data上并且实例可以直接越过data访问属性

    1.通过这句描述可以知道Vue是一个构造函数,并且传入的参数中有一个data的属性,我们可以$data去访问,也可以直接访问这个属性,并且我们需要对这个data做代理那么简单实现如下

    function Vue(options) {this.$data = proxy(options.data())
    }
    function proxy(options) {return new Proxy(options, {get(target, key, value, receiver) {return Reflect.get(target, key, value, receiver)},set(target, key, newValue, receiver) {Reflect.set(target, key, newValue, receiver)}})
    }
    const data = function () {return {a: 'hello world'}
    }
    const vue1 = new Vue({data
    })
    const vue2 = new Vue({data
    })
    vue1.$data.a = 'hello Vue'
    console.log(vue1.$data.a) // hello Vue
    console.log(vue2.$data.a) // hello world 
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    通过简单实现可与看出来,当我们的data是一个函数的时候,在Vue的构造函数中,只有有实例创建就有执行data函数,然后返回一个特别的对象,所以当我们修改其中一个实例的时候并不会对其他实例的数据产生变化那么当data不是一个函数呢 ,我们简单改下代码,代码如下

    function Vue(options) {this.$data = proxy(options.data)
    }
    function proxy(options) {return new Proxy(options, {get(target, key, value, receiver) {return Reflect.get(target, key, value, receiver)},set(target, key, newValue, receiver) {Reflect.set(target, key, newValue, receiver)}})
    }
    const data = {a: 'hello world'
    }
    const vue1 = new Vue({data
    })
    const vue2 = new Vue({data
    })
    vue1.$data.a = 'hello Vue'
    console.log(vue1.$data.a) // hello Vue
    console.log(vue2.$data.a) // hello Vue 
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    可以看出,由于共用一个对象,当代理的时候也是对同一个对象进行代理,那么当我们通过一个实例去改变数据的时候,就会影响其他实例的状态

    最后

    整理了一套《前端大厂面试宝典》,包含了HTML、CSS、JavaScript、HTTP、TCP协议、浏览器、VUE、React、数据结构和算法,一共201道面试题,并对每个问题作出了回答和解析。

    有需要的小伙伴,可以点击文末卡片领取这份文档,无偿分享

    部分文档展示:



    文章篇幅有限,后面的内容就不一一展示了

    有需要的小伙伴,可以点下方卡片免费领取

  • 相关阅读:
    CUDA 中的线程组织
    Web渗透_SQL注入3
    (一)上市企业实施IPD成功案例分享之——方太
    uniapp解决iOS切换语言——原生导航栏buttons文字不生效
    C++ Primer学习笔记-----第三章:字符串、向量、数组
    Codeforces Round #833 (Div. 2) C. Zero-Sum Prefixes
    实验2:Numpy手写多层神经网络
    PyQt5学习系列之新项目创建并使用widget
    kafka 生产者 API 实践总结
    事件总线--EvenBus
  • 原文地址:https://blog.csdn.net/web2022050903/article/details/127730978