前言
在使用Vue开发的过程中,data这个options对于我们来说是最熟悉不过的了。一般来说我们的data通常会写成函数形式,通过return将数据返回,但是官方在以根实例编写demo的时候,我们发现他直接使用了对象的形式。
既然这样,在组件中这样写岂不是更加清爽便利,结果尝试之后,发现给出如下提示:
用我的渣渣英语翻译一下,"data"选项应该是一个函数,并且在组件定义中返回每个实例的值。
emmmmm,"data"选项应该是一个函数???那为什么在根实例中就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)
}
这个init方法会将我们的options传入,做一系列的初始化,包括对数据的初始化,感兴趣的同学可以去Vue源码的src/core/instance/init.js中一探究竟。话不多说,咱们接着看。
在对数据初始化的时候,我们就可以找到对实例的处理
// 在initData时候会先判断data的类型, 在根实例中无论是对象或者是函数类型均会解析
let data = vm.$options.data
data = vm._data = typeofdata === 'function'
? getData(data, vm)
: data || {}
在Vue组件中data的使用
只能为函数
其实在初始化数据之前,Vue在init时候还会先合并options
vm.$options = mergeOptions(
resolveConstructorOptions(vm.constructor),
options|| {},
vm
)
在mergeOptions的合并策略其中有一段会判断是根实例还是组件,并作出处理
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)
}
从上面源码可以看出,如果当前实例判断为!vm,即是普通组件的时候,如果选项类型不是function,会抛出一个错误,即刚才图片中看到的,data选项应该为一个函数。
结论
通过上面的代码,我们可以看出Vue中做了怎样的处理。所以我们可以分析一下Vue这样设计的目的。
在一个项目中,组件可以有多个,每一个组件均可当作一个构造器,注册组件的本质其实就是构造器的引用。如果直接使用对象,他们的内存地址是一样的,一个数据改变了其他也改变了,这就造成了数据污染,如果使用函数的话,会形成一个全新的作用域,这样data中的数据不会相互影响,从而避免数据污染。但由于根实例只有一个,所以不存在数据污染这种情况,也就可以使用对象了。
例子
为了验证上面的结论,我们从原型链出发,写个简单的例子。
const MyComponents = function() {};
MyComponents.prototype.data = {
number:1
};
let component1 = new MyComponents();
let component2 = new MyComponents();
component1.data.number = 2
console.log(component1.data.number, 'component1-data') // 2
console.log(component2.data.number, 'component2-data') // 2
写在最后
Vue中有很多值得我们讨论和注意的细节,并且通过阅读源码我们可以得到最笃定和准确的答案,之后我也会在学习源码的过程中分享一些我的心得和学到的知识,如果有理解错误的地方,希望大家指出来,一起学习,一起进步。
克服恐惧最好的办法就是面对恐惧,加油,奥利给!!!
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。