原因:防止多個元件範例物件之間共用一個data,產生資料汙染;採用函數的形式,initData時會將其作為工廠函數都會返回全新data物件。當將元件中的data寫成一個函數,資料以函數返回值形式定義,這樣每複用一次元件,就會返回一份新的data,擁有自己的作用域,類似於給每個元件範例建立一個私有的資料空間,讓各個元件範例維護各自的資料。
前端(vue)入門到精通課程,老師線上輔導:聯絡老師
Apipost = Postman + Swagger + Mock + Jmeter 超好用的API偵錯工具:
本教學操作環境:windows7系統、vue3版,DELL G3電腦。
一、範例和元件定義data的區別
vue範例的時候定義data屬性既可以是一個物件,也可以是一個函數
const app = new Vue({
el:"#app",
// 物件格式
data:{
foo:"foo"
},
// 函數格式
data(){
return {
foo:"foo"
}
}
})
登入後複製
元件中定義data屬性,只能是一個函數
如果為元件data直接定義為一個物件
Vue.component('component1',{
template:`<div>元件</div>`,
data:{
foo:"foo"
}})
登入後複製
則會得到警告資訊
警告說明:返回的data應該是一個函數在每一個元件範例中
二、元件data定義函數與物件的區別
上面講到元件data必須是一個函數,不知道大家有沒有思考過這是為什麼呢?
在我們定義好一個元件的時候,vue最終都會通過Vue.extend()構成元件範例
這裡我們模仿元件建構函式,定義data屬性,採用物件的形式
function Component(){
}
Component.prototype.data = {
count : 0
}
登入後複製
建立兩個元件範例
const componentA = new Component()
const componentB = new Component()
登入後複製
修改componentA元件data屬性的值,componentB中的值也發生了改變
console.log(componentB.data.count) // 0
componentA.data.count = 1
console.log(componentB.data.count) // 1
登入後複製
產生這樣的原因這是兩者共用了同一個記憶體地址,componentA修改的內容,同樣對componentB產生了影響。【學習視訊分享:、】
如果我們採用函數的形式,則不會出現這種情況(函數返回的物件記憶體地址並不相同)
function Component(){
this.data = this.data()
}
Component.prototype.data = function (){
return {
count : 0
}
}
登入後複製
修改componentA元件data屬性的值,componentB中的值不受影響
console.log(componentB.data.count) // 0
componentA.data.count = 1
console.log(componentB.data.count) // 0
登入後複製
vue元件可能會有很多個範例,採用函數返回一個全新data形式,使每個範例物件的資料不會受到其他範例物件資料的汙染
三、原理分析
首先可以看看vue初始化data的程式碼,data的定義可以是函數也可以是物件
原始碼位置:/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 || {}
...
}
登入後複製
data既能是object也能是function,那為什麼還會出現上文警告呢?
別急,繼續看下文
元件在建立的時候,會進行選項的合併
原始碼位置:/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型別不是function,則出現警告提示
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物件
說明:
vue中元件是用來複用的,為了防止data複用,將其定義為函數。
vue元件中的data資料都應該是相互隔離,互不影響的,元件每複用一次,data資料就應該被複制一次,之後,當某一處複用的地方元件內data資料被改變時,其他複用地方元件的data資料不受影響,就需要通過data函數返回一個物件作為元件的狀態。
當我們將元件中的data寫成一個函數,資料以函數返回值形式定義,這樣每複用一次元件,就會返回一份新的data,擁有自己的作用域,類似於給每個元件範例建立一個私有的資料空間,讓各個元件範例維護各自的資料。
當我們元件的date單純的寫成物件形式,這些範例用的是同一個建構函式,由於JavaScript的特性所導致,所有的元件範例共用了一個data,就會造成一個變了全都會變的結果。
(學習視訊分享:、)
以上就是vue元件中data為啥是函數的詳細內容,更多請關注TW511.COM其它相關文章!