官方解釋:
當你把一個普通的 JavaScript 對象傳給 Vue 實例的 data 選項,Vue 將遍歷此對象所有的屬性,並使用 Object.defineProperty 把這些屬性全部轉為 getter/setter。
不是在data上添加的屬性,因為在實例化是沒有使用Object.definePrototype設置屬性的getter/setter,watcher沒有創建這些屬性的依賴,所以當數據變化時,無法獲取到數據更改的通知,也就不能觸發視圖re-render。
查看vue的源代碼,加載源代碼后,會首先調用initMixin構建Vue。只有當使用new實例化Vue時才會調用_init,並且這時options里的data還只是原生對象
接着調用initState,用來初始化一些需要響應式式處理的數據,方法。包含props,data,computed,watch,methods(將方法的對象設置為當前vue實例,並且判斷方法名是否和props有重復的)。
如果options參數里沒有data,就默認給一個空的,然后直接調用observe對data里的屬性創建觀察者實例
調用initData,做數據檢查,是否是原生對象,檢查data對象里的屬性是否和props對象的屬性有重合的。然后調用observe(),對data對象里的每個屬性創建一個觀察者對象。
調用Observer回調函數(保證每個Vue實例/組件的data都是獨立的,不會造成作用域污染),定義觀察者類,一旦被觀察者對象應用了Observer類,就會將對象的每個屬性設置成getter/setter,從而收集依賴和觸發更新
調用def方法,這個方法的作用就是最后執行Object.definePrototype,將每個data里的屬性設置為getter/setter。
至此,所有具有響應式的屬性都在initState被初始化了和監聽了。
如果想要動態添加數據到data對象上,就需要用到Vue.set方法,首先會判斷是否是數據,然后如果對象上存在屬性(key)就直接設置target[key] = val;接着檢查是否是Vue實例,是否應被設置為觀察者對象;只有已經被設置為觀察者對象的對象,才能調用Vue.set動態添加屬性和值;這也就是管網API上說的
注意對象不能是 Vue 實例,或者 Vue 實例的根數據對象。