vue源碼研究--Data爲啥要寫成函數?

大家在使用vue的時候,肯定有想過爲什麼 data 要寫成函數,而不允許寫成對象?
首先我們要想到:

  1. data是 Vue 實例上的一個屬性。
  2. 對象是對於內存地址的引用。
  3. 函數有自己的作用域空間。
    vue 實例中的data是對象的寫法,但是在組件中data是函數的寫法,是因爲寫成函數,會有函數作用域的概念 ,是私有函數,只作用到當前組件中,不會影響到其它各個不同的組件。

第一點無可厚非,data屬性附着於 Vue 實例上。

第二點,JS 的數據類型分爲基本類型和引用類型,基本類型存儲在棧內存中,引用類型存儲在堆內存中,並且引用類型指向的是棧內存中的堆區地址。下面兩個例子可以幫助你清晰地理解這句話。
基本數據類型賦值:

var a = 10;
var b = 10;
var c = a;
console.log(a === b); // true 
a ++ ;
console.log(a); // 11
console.log(c); // 10
a變化了 c沒有變化

這段代碼分別給 a、b 賦值 10,a 和 b 是全等的。然後用 a 來初始化 c,那麼 c 的值也是 10。但 c 中的 10 與 a 中的是完全獨立的,該值只是 a 中的值的一個副本,此後, 這兩個變量可以參加任何操作而相互不受影響。具體位置如下示意圖。
在這裏插入圖片描述
引用類型賦值

var a = {};
var b = {};
var c = a;
console.log(a === b); // false
a.name = 'Marry';
a.say = () => console.log('Hi Marry!');
console.log(c.name); // 'Marry'
console.log(c.say()); // 'Hi Marry!'

上面這段代碼。首先聲明瞭a、b兩個空對象,然後把 a 賦值給 c。因爲對象是對棧內存的地址的引用,所以不同的對象的地址是不同的,所以他們不是全等的。接着給 a 新增加屬性和方法,c 同樣可以擁有此屬性和方法,主要是因爲 c 和 a 指向堆內存中的同一個地址。其關係圖如下示意圖所示。
在這裏插入圖片描述
至於第三點,大多數有 JS 基礎的同學應該都能理解,每個函數都有自己的作用域。

以上是對三個注意點的說明,那麼接下來我們就以兩個例子解釋問題一:爲什麼 data 要寫成函數,而不允許寫成對象?
data 爲對象示例代碼

function MyCompnent() {}
MyCompnent.prototype.data = {
  age: 12
};
var JackMa = new MyCompnent();
var PonyMa = new MyCompnent();
console.log(JackMa.data.age === PonyMa.data.age); // true
JackMa.data.age = 13;
console.log('JackMa ' + JackMa.data.age + '歲;' + 'PonyMa ' + PonyMa.data.age + '歲'); 
// JackMa 13歲;PonyMa 13歲

上面的示例中,我們創建一個構造函數 MyCompnent,它充當的角色相當於 Vue,在他的原型屬性上聲明一個data屬性,其實也相當於 Vue.$data。接着聲明兩個實例,改變其中一個實例,另外一個實例也會跟着改變,這個道理其實和引用類型賦值大同小異。
Tips:
關於構造函數的prototype繼承原理,請參考詳細解釋:
面向對象的詳細理解與繼承方法對比
data 爲函數的示例代碼

function MyCompnent() {
  this.data = this.data();
}

MyCompnent.prototype.data = function() {
  return {
    age: 12
  }
};

var JackMa = new MyCompnent();
var PonyMa = new MyCompnent();

console.log(JackMa.data.age === PonyMa.data.age); // true

JackMa.data = {age: 13};

console.log('JackMa ' + JackMa.data.age + '歲;' + 'PonyMa ' + PonyMa.data.age + '歲');
// JackMa 13歲;PonyMa 12歲

上述代碼模擬了 Vue 實例上的data爲函數的時候,如果改變一個實例的data屬性的值,那麼不會影響到另外一個實例上的data的值。

Vue 裏面data屬性之所以不能寫成對象的格式,是因爲對象是對地址的引用,而不是獨立存在的。如果一個.vue 文件有多個子組件共同接收一個變量的話,改變其中一個子組件內此變量的值,會影響其他組件的這個變量的值。如果寫成函數的話,那麼他們有一個作用域的概念在裏面,相互隔閡,不受影響。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章