咱們先參考vue官網給出的解釋:vue
一個組件的
data
選項必須是一個函數,使得每一個實例能夠維護一份被返回對象的獨立的拷貝api
首先,咱們先看一個簡單的原型鏈有關知識。markdown
`function VueComponent(){}
VueComponent.prototype.$options = {
data:{
name:'zf',
}
}
let vc1 = new VueComponent()
vc1.$options.data = 'lx'
let vc2 = new VueComponent()
console.log(vc2.$options.data)`
複製代碼
咱們能夠看到,實例對象VC1修改了name的值爲「lx」,新的實例對象VC2訪問到的值也是修改後的「lx」。函數
這是由於VC1和VC2兩個實例對象在操做$options時是在操做VueComponent構造函數原型對象上的屬性,實例對象的隱式原型屬性等於其構造函數的顯示原型屬性,因此它們指向的是同一塊內存空間。 這致使了兩個對象數據不獨立,會相互污染。spa
根據以上結果,再回到咱們Vue組件中的data屬性。prototype
同一個組件被複用屢次,會建立多個實例。這些實例用的是同一個構造函數,若是 data 是一個對象的話,那麼全部組件都共享了同一個對象。爲了保證組件的數據獨立性要求每一個組件必須經過 data 函數返回一個對象做爲組件的狀態。code
core/global-api/extend.js line:33
component
Sub.options = mergeOptions(Super.options, extendOptions)
function mergeOptions() {
function mergeField(key) {
const strat = strats[key] || defaultStrat options[key] = strat(parent[key], child[key], vm, key)
}
}
strats.data = function(parentVal: any, childVal: any, vm ? : Component
): ? Function {
if (!vm) { // 合併是會判斷子類的data必須是一個函數
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必須是一個函數,這樣組件間不會相互影響。orm