vue初始化data方法有兩種:1、object方式,語法「var data = { 鍵值對 }」;2、function方式,語法「data: function () {return { 鍵值對 }}」。需要注意元件和extend中的data初始化不能是Object,否則會報錯。元件中data用function方式是為了防止多個元件範例物件之間共用一個data,產生資料汙染。
本教學操作環境:windows7系統、vue3版,DELL G3電腦。
vue data有兩種初始化的方式,function和object,但是這兩種情況適用場景有哪些?能不能通用?帶著這兩個問題咱們一起分析下
data初始化
// 程式碼來源於官網範例
// 第一種定義方式
var data = { a: 1 }
// 直接建立一個範例
var vm = new Vue({
data: data
})
// Vue.extend() 中 data 必須是函數
var Component = Vue.extend({
// 第二種定義方式
data: function () {
return { a: 1 }
}
})
登入後複製
上述程式碼簡單描述了data定義的兩種方式
function
object
官網demo中也著重說了extend中data初始化不能用object。那麼為什麼呢?
原始碼分析
按照官網demo,Vue.extend中的data初始化不能是Object,如果我們強制寫成Object會出現什麼?
var Component = Vue.extend({
data: { a: 1 }
})
登入後複製
執行以後chrome的consolo直接報錯,資訊如下
vue.esm.js?efeb:591 [Vue warn]: The "data" option should be a function that returns a per-instance value in component definitions.
登入後複製
通過分析原始碼以及報錯資訊,當觸發Vue.extend的時候,他會做一個合併操作,把一個基礎元件(裡面vmode, transtion等)和你定義在extend內的資訊,通過mergeField往options上合併,當合併到data的時候,他會觸發strats.data,在這個裡面會check data是不是一個function,這裡需要注意的是filter、components等和data走的是兩套合併流程,詳細的請看程式碼註釋,如下
// vue.extend 原始碼地址https://github.com/vuejs/vue/blob/dev/src/core/global-api/extend.js
Vue.extend = function (extendOptions: Object): Function {
...
// 在這裡會觸發mergeOptions方法
Sub.options = mergeOptions(
Super.options,
extendOptions
)
...
}
// mergeOptions 原始碼地址https://github.com/vuejs/vue/blob/dev/src/core/util/options.js
export function mergeOptions (
parent: Object,
child: Object,
vm?: Component
): Object {
...
const options = {}
let key
// parent物件內包含components、filter,、directive
for (key in parent) {
mergeField(key)
}
// child物件內對應的是Vue.extend內定義的引數
for (key in child) {
if (!hasOwn(parent, key)) {
mergeField(key)
}
}
function mergeField (key) {
// 這一步是根據傳入的key找到不同的合併策略filter、components、directives用到合併策略是這個方法mergeAssets和data用到的不一樣,當合併到data的時候會進入專屬的合併策略方法內
const strat = strats[key] || defaultStrat
options[key] = strat(parent[key], child[key], vm, key)
}
}
// strats.data 原始碼地址https://github.com/vuejs/vue/blob/dev/src/core/util/options.js
strats.data = function (
parentVal,
childVal,
vm
) {
if (!vm) {
// 如果data不是function的話會直接走下面的報錯資訊
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定義為一個物件,因為他們底層都呼叫了mergeOptions方法
什麼時候可以定義成一個物件
在vue初始化的時候,如下
new Vue({
data: {
linke: '//sinker.club'
}
})
登入後複製
意義
ok,上面說了那麼多,那麼這麼做的意義是什麼?為什麼那幾種情況不可以定義為物件? 其實回答這個問題,需要回到js本身,眾所周知js資料型別分為參照和基本,參照型別包含Object, Array, Function,何為參照型別就不在這裡闡述了
var obj = {link: '//www.sinker.club'}
var obj2 = obj
var obj3 = obj
obj2.link = "//gitlab.sinker.club"
console.log(obj3.link) // "//gitlab.sinker.club"
登入後複製
上述程式碼反應了一個問題,由於obj3和obj2在記憶體中都是指向一個地址,那麼obj2的修改會影響到obj3,當然處理這種問題可以用深copy來做到
JSON.parse(JSON.stringify(obj))
deepClone(obj)
但是這兩種做法需要開發或者框架每一次都要深copy一次,當資料量大的時候對效能什麼都不友好,那麼Vue怎麼做的呢?把data定義成一個function
function data() {
return {
link: '//sinker.club'
}
}
var obj = test()
var obj2 = test()
obj2.link ="//gitlab.sinker.club"
console.log(obj.link) '//sinker.club'
登入後複製
為什麼這麼做?解決的場景是什麼呢?
比如我定一個子元件,data是按照物件的方式定義的,這個元件在多個地方參照,如果其中一個參照此元件的data修改了,那麼就會造成其餘參照此元件的data同時改變, end.
擴充套件知識:
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"
}})
登入後複製
則會得到警告資訊
說明:
vue中元件是用來複用的,為了防止data複用,將其定義為函數。
vue元件中的data資料都應該是相互隔離,互不影響的,元件每複用一次,data資料就應該被複制一次,之後,當某一處複用的地方元件內data資料被改變時,其他複用地方元件的data資料不受影響,就需要通過data函數返回一個物件作為元件的狀態。
當我們將元件中的data寫成一個函數,資料以函數返回值形式定義,這樣每複用一次元件,就會返回一份新的data,擁有自己的作用域,類似於給每個元件範例建立一個私有的資料空間,讓各個元件範例維護各自的資料。
當我們元件的date單純的寫成物件形式,這些範例用的是同一個建構函式,由於JavaScript的特性所導致,所有的元件範例共用了一個data,就會造成一個變了全都會變的結果。
【相關推薦:、】
以上就是vue初始化data方法有哪些的詳細內容,更多請關注TW511.COM其它相關文章!