2. The data of the root instance is an object. Why is the data of the component a function?
Create a demo
<! DOCTYPEhtml>
<html>
<head>
<title>Vue_data</title>
<body>
<div id="demo">
<h3>Why is the data component a function?</h3>
<subcomponents></subcomponents>
<subcomponents></subcomponents>
{{counter}}
</div>
<script src=".. /.. /dist/vue.js"></script>
<script>
// Create an instance
Vue.component('subcomponents', {
template: '<div @click="childCounter++">{{childCounter}}</div>'./* data: {// The "data" option should be a function that returns a per-instance value in component definitions. childCounter: 0 } */
data () {
return {
childCounter: 0}}})const app = new Vue({
el: '#demo'.data: {
counter: 1}});console.log(app.$options.render);
</script>
</body>
</html>
Copy the code
Source location
Url SRC \core\instance\init.js find initState => initData
init.js
// expose real self
vm._self = vm
initLifecycle(vm) $parent $root $refs $children
initEvents(vm) // Custom event handling
initRender(vm) $slots $createElement()
// No data is available at this time
callHook(vm, 'beforeCreate')
// All subsequent data operations related to component state
initInjections(vm) // Inject data passed by grandparents
initState(vm) / / find the baby -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- I AM HERE!!
initProvide(vm) // Pass to descendant, used to pass parameters between generations
callHook(vm, 'created')
-----------------------------------------------------------------------------------------
state.js
export function initState (vm: Component) {
vm._watchers = []
const opts = vm.$options
// Priority > methods > Data > computed > Watch
if (opts.props) initProps(vm, opts.props)
if (opts.methods) initMethods(vm, opts.methods)
if (opts.data) {
// Set data to data
initData(vm) // ---------------------------------------------- I AM HERE!!
} else {
observe(vm._data = {}, true /* asRootData */)}if (opts.computed) initComputed(vm, opts.computed)
if(opts.watch && opts.watch ! == nativeWatch) { initWatch(vm, opts.watch) } } ------------------------------------------------------------------------------------------- state.jsfunction initData (vm: Component) {
let data = vm.$options.data
// If data is a function, it executes the function and returns the result as the value of the data option
data = vm._data = typeof data === 'function'
? getData(data, vm) // I am the code for the perfect couple
: data || {}
// proxy data on instance
// check to avoid naming conflicts
const keys = Object.keys(data)
const props = vm.$options.props
const methods = vm.$options.methods
while (i--) {
---
}
// observe data
// Recursive response processing
observe(data, true /* asRootData */)}Copy the code
Conclusion: If the component defines the object data, the data will be referred to the same object, resulting in data contamination. Therefore, in case of multiple instances, a new object is returned via the factory function to avoid data contamination. But the question arises, why can the data of the root instance be an object? The root instance is created with a new Vue because the Vue is created only once. For this reason, I will go to the source code to find the answer
Source location
url src\core\instance\init.js
// Merge options: when new Vue, user configuration and system configuration are merged
if (options && options._isComponent) { // The component goes here
// 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 { // The root instance goes herevm.$options = mergeOptions( resolveConstructorOptions(vm.constructor), options || {}, Vm)} -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- - processing data strats. Data =function (parentVal: any, childVal: any, vm? : Component): ?Function {
if(! vm) {if (childVal && typeofchildVal ! = ='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) // The component instance has no VM
}
// The root instance exists in vm
return mergeDataOrFn(parentVal, childVal, vm)
}
Copy the code
Conclusion: The Component => constructor (used to merge Vue’s methods onto the current instance) has not created the current Component instance. When merging components, verify that the data root instance => constructor has a VM
conclusion
- Vue components may have multiple instances. If data is defined with an object, one data object will be shared. Then, when the state changes, all component instances will be affected
- When a Vue root instance is created, there is an instance, whereas when a component instance is created, there is no instance and there is only one root instance, so there is no data contamination