Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

153.[vue]Vue组件data为什么必须是个函数而Vue的根实例则没有此限制? #153

Open
webVueBlog opened this issue Apr 2, 2020 · 3 comments
Labels
vue vue

Comments

@webVueBlog
Copy link
Member

[vue]

@webVueBlog webVueBlog added the vue vue label Apr 2, 2020
@webVueBlog
Copy link
Member Author

注册组件的本质其实就是建立一个组件构造器的引用。使用组件才是真正创建一个组件实例。所以,注册组件其实并不产生新的组件类,但会产生一个可以用来实例化的新方式。

vue组件实例化后,同一组件不同的实例引用同一个data对象(函数)。

对于vue组件来说,要保证复用性,data必须是函数,返回一个对象,这样多个组件实例就能得到返回对象独立的拷贝。

对于vue根实例来说,因为只实例化一次,所以data可以是对象或函数

@webVueBlog
Copy link
Member Author

组件data为函数缘由

在创建或注册模板的时候传入一个 data 属性作为用来绑定的数据。但是在组件中,data必须是一个函数,因为每一个 vue 组件都是一个 vue 实例,通过 new Vue() 实例化,引用同一个对象,如果 data 直接是一个对象的话,那么一旦修改其中一个组件的数据,其他组件相同数据就会被改变,而 data 是函数的话,每个 vue 组件的 data 都因为函数有了自己的作用域,互不干扰。

@webVueBlog
Copy link
Member Author

在使用Vue开发的过程中,data这个options对于我们来说是最熟悉不过的了。一般来说我们的data通常会写成函数形式,通过return将数据返回,但是官方在以根实例编写demo的时候,我们发现他直接使用了对象的形式。

"data"选项应该是一个函数,并且在组件定义中返回每个实例的值。

从源码级别看一下,Vue中究竟做了什么处理。

在Vue根实例中data的使用

可以为函数,可以为对象

vue的实例的时候会调用一个init方法

function Vue (options) {
        if (process.env.NODE_ENV!=='production'&& !(thisinstanceofVue)) {
            warn('Vue is a constructor and should be called with the`new` keyword')
        }

        this._init(options)
    }
// 在initData时候会先判断data的类型, 在根实例中无论是对象或者是函数类型均会解析

    let data = vm.$options.data

    data = vm._data = typeofdata === 'function'
        ? getData(data, vm)
        : data || {}

在Vue组件中data的使用

只能为函数

    vm.$options = mergeOptions(
        resolveConstructorOptions(vm.constructor),
        options|| {},
        vm
    )
strats.data = function (
    parentVal:any,
    childVal:any,
    vm?:Component
    ):?Function {
        if (!vm) {
            if (childVal&&typeof childVal!=='function') {
                process.env.NODE_ENV!=='production'&&warn('The "data" option should be a function '+'that returns a per-instance value in component '+'definitions.', vm)
                return parentVal
            }
            return mergeDataOrFn(parentVal, childVal)
        }
        return mergeDataOrFn(parentVal, childVal, vm)
}

在一个项目中,组件可以有多个,每一个组件均可当作一个构造器,注册组件的本质其实就是构造器的引用。如果直接使用对象,他们的内存地址是一样的,一个数据改变了其他也改变了,这就造成了数据污染,如果使用函数的话,会形成一个全新的作用域,这样data中的数据不会相互影响,从而避免数据污染。但由于根实例只有一个,所以不存在数据污染这种情况,也就可以使用对象了。

    const MyComponents = function() {};
    
    MyComponents.prototype.data = {
        number:1
    };
    
    let component1 = newMyComponents();
    let component2 = newMyComponents();
    
    component1.data.number = 2
    console.log(component1.data.number, 'component1-data') // 2
    console.log(component2.data.number, 'component2-data') // 2

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
vue vue
Projects
None yet
Development

No branches or pull requests

1 participant