组件data定义函数与对象的区别 在我们定义好一个组件的时候,vue最终都会通过Vue.extend()构成组件实例
1 2 3 4 5 6 function Component ( ) { } Component.prototype.data={ count :0 }
创建两个组件实例:
1 2 3 4 5 const componentA=new Component()const componentB=new Component();console .log(componentB.data.count);componentA.data.count=1 ; console .log(componentB.data.count)
产生这样的原因是两者共用了同一个内存地址,compoentA修改的内容,同样对componentB产生了影响
如果采用函数形式,则不会出现这种情况(函数返回的对象内存地址并不相同)
1 2 3 4 5 6 7 8 function Component ( ) { this .data = this .data() } Component.prototype.data = function ( ) { return { count : 0 } }
1 2 3 4 console .log(componentB.data.count) componentA.data.count = 1 console .log(componentB.data.count)
vue组件可能有多个实例,采用函数返回一个全新data形式,使每个实例对象的数据不会受到其他实例对象数据的污染
原理: vue初始化data的代码时,data的定义可以是函数或者对象
1 2 3 4 5 6 7 function initData (vm: Component ) { let data = vm.$options.data data = vm._data = typeof data === 'function' ? getData(data, vm) : data || {} ... }
但是组件在创建的时候,会进行选项的合并,自定义组件会进入mergeOptions进行选择合并
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 Vue.prototype._init = function (options?: Object ) { ... if (options && options._isComponent) { initInternalComponent(vm, options) } else { vm.$options = mergeOptions( resolveConstructorOptions(vm.constructor), options || {}, vm ) } ... }
定义data会进行数据校验
这时候vm实例为undefined,进入if判断,若data类型不是function,则出现警告提示
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 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可以是对象也可以是函数(根实例是单例 ),不会产生数据污染情况
组件实例对象data必须是函数 ,目的是为了防止多个组件实例对象之间共用一个data,产生数据污染,采用函数的形式,initData时会将其作为工厂函数返回全新data对象