剖析vue常见问题(二)之组件的data为什么要定义为函数,而根实例的data则没有限制?

背景:vue组件化是它的特点,经常定义组件的我们会知道把组件的data定义为函数,也知道是为了避免数据污染,而根实例则没有强制要求(因为根实例是单例,不用担心数据污染),具体原因是什么呢?我们也从源码来做分析吧,详见源码:src/core/instance/state.js中的initData()方法,当然我们也用demo来说明,demo如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>vue data</title>
</head>
<body>
    <div>vue组件data为什么必须是个函数而Vue的根实例则没有限制?源码中详见:src/core/instance/state.js中的initData()</div>


    <div id="demo">
       <div>vue组件data为什么必须是个函数?</div>
       <comp></comp>
       <comp></comp>
       <div>{
   
   {counter}}</div>
    </div>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <script>
        Vue.component('comp',{
            template:'<div @click="counter++">{
   
   {counter}}</div>',
            // data: {counter: 0}如果这么定义首先会报错,要求data为函数,原因是为了避免多个组件数据互相影响,造成数据污染,一会从源码中解释
            data () {
                return {
                    counter:1
                }
            }
        })
        //创建实例
        const app = new Vue({
            el: '#demo',
            data:{counter:1}
        });
        console.log(app.$options.render);
    </script>
</body>
</html>

1.源码解释组件data必须为函数的原因如下:

由上可以看出,如果是组件不采用函数会造成数据公用的情况,造成数据污染。

2.刚才也说过根组件data没有限制,一是因为const app = new Vue({el:'#demo'})是单例,另外也可以从源码中分析如下:/src/core/instance/init.js

通过给mergeoptions加断点发现,自定义组建会先执行,然后走根组件,源码位置:/src/core/util/options.js,具体详见合并策略,如下:

由上可以看出,当走自定义组件时vm不存在才走判断,如果当根组件实例创建之后就不会走条件检测了,所以根组件中data不用定义为函数。

综上得出以下结论:

vue组件可能存在多个实例,直接使用对象的形式定义data,会导致组件共用一个data对象,状态变更会影响所有的组件实例,这是不合理的。采用函数的形式,在initData时会将其作为工厂函数返回全新的data对象,避免了实例之间状态污染的问题。而vue根实例创建过程中不存在该限制,是因为根实例只有一个不需要担心这个问题。

综上,说明了为什么vue的自定义组件的data需要定义为函数,而根实例则没有此限制的原因,希望对大家有所帮助,以上,谢谢。

猜你喜欢

转载自blog.csdn.net/wh_xmy/article/details/109599347