Vue 组件 data为什么是函数?

首先,我们看Vue官网解释

data必须是一个函数
当我们定义这个 <button-counter> 组件时,你可能会发现它的 data 并不是像这样直接提供一个对象:

data: {
  count: 0
}

取而代之的是,一个组件的 data 选项必须是一个函数,因此每个实例可以维护一份被返回对象的独立的拷贝:

data: function () {
  return {
    count: 0
  }
}

如果 Vue 没有这条规则,点击一个按钮就可能会像如下代码一样影响到其它所有实例

官网上还提到

把一个普通 Javascript 对象传给 Vue 实例的 data 选项,Vue 将遍历此对象所有的属性,并使用 Object.defineProperty 把这些属性全部转为 getter/setter。Object.defineProperty 是仅 ES5 支持,且无法 shim 的特性,这也就是为什么 Vue 不支持 IE8 以及更低版本浏览器的原因。

OK,现在我们来举个🌰

var option = {
        data: {
            a: 1
        }
    }
    class component {
        constructor(opt) {
            this.data = opt.data;
            Object.defineProperty(this.data, `a`, {
                get: function () {
                    console.log('get val');
                    return this._a;
                },
                set: function (newVal) {
                    console.log('set val:' + newVal);
                    this._a = newVal;
                }
            });
        }
    }

    var c1 = new component(option);
    var c2 = new component(option);
    c1.data.a = 3;
    c2.data.a = 5;
    console.log(`c1 : ` + c1.data.a);//c1 : 5
    console.log(`c2 : ` + c2.data.a);//c2 : 5
示例代码中 Object.defineProperty 把传进来组件中的data 的 a 属性转化为 getter 和 setter,可以实现 data.a 的数据监控。这个转化是 Vue.js 响应式的基石。

这样就不难理解data为什么不能是对象了,如果传进来是对象,new出来的两个实例同时引用一个对象,那么当你修改其中一个属性的时候,另外一个实例也会跟着改。

现在我们修改一下

    var option = {
        data: function () {
            return {a: 1}
        }
    }

    class component {
        constructor(opt) {
             this.data = opt.data();
            Object.defineProperty(this.data, `a`, {
                get: function () {
                    console.log('get val');
                    return this._a;
                },
                set: function (newVal) {
                    console.log('set val:' + newVal);
                    this._a = newVal;
                }
            });
        }
    }

    var c1 = new component(option);
    var c2 = new component(option);
    c1.data.a = 3;
    c2.data.a = 5;
    console.log(`c1 : ` + c1.data.a);//c1 : 3
    console.log(`c2 : ` + c2.data.a);//c2 :5

传进去一个函数,这样每一个实例的data属性都是独立的,不会相互影响了。

总结:

对象是对于内存地址的引用。直接定义个对象的话,组件之间都会使用这个对象,这样会造成组件之间数据相互影响。组件就是为了抽离开来提高复用的, 如果组件之间数据默认存在关系,就违背了组件的意义。 函数 return 一个新的对象,其实还是为 data 定义了一个对象, 只不过这个对象是内存地址的单独引用了,这样组件之间就不会存在数据干扰的问题。

以上为个人理解,如果有误,请指出,谢谢。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。