1.实例与组件定义data的区别
1.1首先我们得分清楚啥是Vue实例,啥是组件?
vue 实例代表着整个 Vue 应用程序。它可以管理整个应用程序的状态,包括所有的组件、模板等。而 vue 组件实例只代表一个组件。每个组件都拥有自己的独立作用域,这意味着我们必须在组件之间传递参数来共享状态。
vue 实例可以挂载到任何 HTML 元素上,并绑定该元素上的事件。 而组件实例不能够直接被挂载,只能放在组件标签中使用。
在 vue 组件中,父组件可以通过 props 属性将数据传递给子组件进行渲染,并在子组件触发事件时更新父组件的数据。而在 vue 实例中,没有父子关系,但是不同的实例之间可以通过 EventBus 或 Vuex 等方式进行通信。
总的说就是实例中有el属性挂载指定的元素,而组件没有,只能通过调用组件名渲染
vue实例的html元素是直接渲染到页面中,而组件的html元素是定义在template上,通过调用再渲染到页面
1.2 定义data的区别
实例定义data可以是一个函数,也可以是一个对象
组件定义data只能是一个函数,否则会报错
2.组件函数式与对象式data的区别
在我们定义一个组件时,vue最终都会通过vue.extend()构成组件实例,由于一个组件可能会有多个实例,采用函数返回一个全新的data形式,使得每个实例对象之间的数据相互间不受影响。而根实例是单例,不会出现多个实例对象,因此不存在数据污染情况。
3.原理分析
源码位置:/vue-dev/src/core/instance/state.js
function initData(vm: Component) {
let data = vm.$options.data
data = vm._data = typeof data === 'function'
? getData(data, vm)
: data || {}
...
}
组件在创建的时候,会进行选项的合并
源码位置:/vue-dev/src/core/util/options.js
自定义组件会进入mergeOptions进行选项合并
Vue.prototype._init = function (options?: Object) {
...
// merge options
if (options && options._isComponent) {
// optimize internal component instantiation
// since dynamic options merging is pretty slow, and none of the
// internal component options needs special treatment.
initInternalComponent(vm, options)
} else {
vm.$options = mergeOptions(
resolveConstructorOptions(vm.constructor),
options || {},
vm
)
}
...
}
定义data时会进行数据检验
源码位置:/vue-dev/src/core/instance/init.js
这时候vm实例是undefined,进入if判断,若data不是函数类型,则报错
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);
};