1. MVC的定義:MVC是Model-View-Controller的簡寫。即模型-視圖-控制器。M和V指的意思和MVVM中的M和V意思一樣。C即Controller指的是頁面業務邏輯。使用MVC的目的就是將M和V的代碼分離。MVC是單向通信。也就是View跟Model,必須通過Controller來承上啟下。MVC和MVVM的區別並不是VM完全取代了C,ViewModel存在目的在於抽離Controller中展示的業務邏輯,而不是替代Controller,其它視圖操作業務等還是應該放在Controller中實現。也就是說MVVM實現的是業務邏輯組件的重用。由於mvc出現的時間比較早,前端並不那么成熟,很多業務邏輯也是在后端實現,所以前端並沒有真正意義上的MVC模式。
- View 傳送指令到 Controller
- Controller 完成業務邏輯后,要求 Model 改變狀態
- Model 將新的數據發送到 View,用戶得到反饋
2. Mvvm定義MVVM是Model-View-ViewModel的簡寫。即模型-視圖-視圖模型。【模型】指的是后端傳遞的數據。【視圖】指的是所看到的頁面。【視圖模型】mvvm模式的核心,它是連接view和model的橋梁。它有兩個方向:一是將【模型】轉化成【視圖】,即將后端傳遞的數據轉化成所看到的頁面。實現的方式是:數據綁定。二是將【視圖】轉化成【模型】,即將所看到的頁面轉化成后端的數據。實現的方式是:DOM 事件監聽。這兩個方向都實現的,我們稱之為數據的雙向綁定。總結:在MVVM的框架下視圖和模型是不能直接通信的。它們通過ViewModel來通信,ViewModel通常要實現一個observer觀察者,當數據發生變化,ViewModel能夠監聽到數據的這種變化,然后通知到對應的視圖做自動更新,而當用戶操作視圖,ViewModel也能監聽到視圖的變化,然后通知數據做改動,這實際上就實現了數據的雙向綁定。並且MVVM中的View 和 ViewModel可以互相通信。MVVM流程圖如下:

我們講一下主流框架實現雙向綁定(響應式)的做法:
1. 臟值檢查:angular,angular.js是通過臟值檢測的方式比對數據是否有變更,來決定是否更新視圖,最簡單的方式就是通過 setInterval() 定時輪詢檢測數據變動,當然Google不會這么low,angular只有在指定的事件觸發時進入臟值檢測,大致如下: DOM事件,譬如用戶輸入文本,點擊按鈕等。( ng-click ) XHR響應事件 ( $http ) 瀏覽器Location變更事件 ( $location ) Timer事件( $timeout , $interval ) 執行 $digest() 或 $apply()。在Angular中組件是以樹的形式組織起來的,相應地,檢測器也是一棵樹的形狀。當一個異步事件發生時,臟檢查會從根組件開始,自上而下對樹上的所有子組件進行檢查,這種檢查方式的性能存在很大問題。
2.觀察者-訂閱者(數據劫持):vue,Observer 數據監聽器,把一個普通的 JavaScript 對象傳給 Vue 實例的 data 選項,Vue 將遍歷此對象所有的屬性,並使用Object.defineProperty()方法把這些屬性全部轉成setter、getter方法。當data中的某個屬性被訪問時,則會調用getter方法,當data中的屬性被改變時,則會調用setter方法。Compile指令解析器,它的作用對每個元素節點的指令進行解析,替換模板數據,並綁定對應的更新函數,初始化相應的訂閱。Watcher 訂閱者,作為連接 Observer 和 Compile 的橋梁,能夠訂閱並收到每個屬性變動的通知,執行指令綁定的相應回調函數。Dep 消息訂閱器,內部維護了一個數組,用來收集訂閱者(Watcher),數據變動觸發notify 函數,再調用訂閱者的 update 方法。執行流程如下:

從圖中可以看出,當執行 new Vue() 時,Vue 就進入了初始化階段,一方面Vue 會遍歷 data 選項中的屬性,並用 Object.defineProperty 將它們轉為 getter/setter,實現數據變化監聽功能;另一方面,Vue 的指令編譯器Compile 對元素節點的指令進行解析,初始化視圖,並訂閱Watcher 來更新視圖, 此時Wather 會將自己添加到消息訂閱器中(Dep),初始化完畢。當數據發生變化時,Observer 中的 setter 方法被觸發,setter 會立即調用Dep.notify(),Dep 開始遍歷所有的訂閱者,並調用訂閱者的 update 方法,訂閱者收到通知后對視圖進行相應的更新。因為VUE使用Object.defineProperty方法來做數據綁定,而這個方法又無法通過兼容性處理,所以Vue 不支持 IE8 以及更低版本瀏覽器。另外,查看vue原代碼,發現在vue初始化實例時, 有一個proxy代理方法,它的作用就是遍歷data中的屬性,把它代理到vm的實例上,這也就是我們可以這樣調用屬性:vm.aaa等於vm.data.aaa。好了,關於mvvm設計模式及vue的雙向綁定原理就講到這。