一.Vue響應式原理
首先要了解幾個概念:
數據響應式:數據模型僅僅是普通的Javascript對象,而我們修改數據時,視圖會進行更新,避免了繁瑣的DOM操作,提高開發效率。
雙向綁定:數據改變,視圖改變,數據也隨之改變,我們可以使用v-model在表單上創建雙向數據綁定。
數據驅動是Vue最獨特的特性之一:開發過程中僅需要關注數據本身,不需要關心數據是如何渲染到視圖。
vue2.X中的響應式原理是基於defineProperty,兼容IE8以上版本,核心原理代碼如下:
let data={ msg:'hello', count:10 } let vm={} proxyData(data) function proxyData(data){ Object.keys(data).forEach(key=>{ Object.defineProperty(vm,key,{ enumerable:true, configurable:true, writeable:true, //獲取值的時候執行 get(){ console.log('get:',key,data[key]) return data[key] }, //設置值的時候執行 set(newValue){ data[key]=newValue console.log('set:',key,newValue) document.querySelector('#app').textContent=data[key] } }) }) } vm.msg //獲取(get方法) hello vm.msg='hello World' //設置新屬性值並渲染到頁面(set方法) vm.msg //hello World
vue3.X中的響應式原理是基於Proxy,直接監聽對象,而非屬性,ES6中新增,IE不支持,性能由瀏覽器優化,性能比defineProperty要好,代碼的話相比較defineProperty要簡潔一些,對於多個屬性的值不需要進行循環遍歷處理。
let data={ msg:'hello', count:0 } //模擬 Vue 實例 let vm=new Proxy(data,{ //執行代理行為的函數 //當訪問 vm 的成員會執行 get(target,key){ console.log('get,key:',key,target[key]) return target[key] }, set(target,key,newValue){ console.log('set,key:',key,newValue) if(target[key] === newValue){ return } target[key]=newValue document.querySelector("#app").textContent=target[key] } }) //測試 vm.msg='Hello World' console.log(vm.msg)
二.發布訂閱模式和觀察者模式
1.發布/訂閱模式
這個概念有些抽象,下面舉個例子說明下,家長比較關心孩子成績,天天問孩子成績出來沒,假設可以到孩子所在班級去訂閱孩子成績,一旦考試成績出來,相當於觸發了一個事件,最后有班級的老師以短信的形式通知給家長,
不需要天天問孩子成績出來沒,家長就是事件的訂閱者,老師是事件的發布者,孩子所在的班級可以假想成一個事件的中心。vue中的自定義事件都是基於發布/訂閱模式的。下面模擬下發布訂閱模式的運行機制:
//事件觸發器 class EventEmitter(){ constructor(){ // 初始化對象{ 'click':[fn1,fn2],'change':[fn] } this.subs=Object.create(null) } //注冊事件 $on(eventType,handler){ this.subs[eventType] = this.subs[eventType] || [] this.subs[eventType].push(handler) } //觸發事件 $emit(eventType){ if(this.subs[eventType]){ this.subs[eventType].forEach(handler => { handler() }) } } } //測試 let em =new EventEmitter() em.$on('click',()=>{ console.log('click1') }) em.$on('click',()=>{ console.log('click2') }) em.$emit('click') //打印結果 click1,click2
二.觀察者模式
觀察者模式和訂閱模式的區別是沒有事件中心,只有發布者和訂閱者,並且發布者需要知道訂閱者的存在.
概念:
觀察者 --Watcher
update():當事件發生時,具體要做的事情。
發布者 --Dep
subs數組:存儲所有的觀察者
addSub():添加觀察者
notify():當事件發生,調用所有觀察者的update()方法
//發布者-目標 class Dep{ constructor() { //記錄所有的訂閱者 this.subs=[] } //添加訂閱者 addsub(sub){ if(sub && sub.update){ this.subs.push(sub) } } //發布通知 notify(){ this.subs.forEach(sub=>{ sub.update() }) } } //訂閱者-觀察者 class Watcher{ update(){ console.log('update') } } //測試 let dep=new Dep() let watcher=new Watcher() dep.addsub(watcher) dep.notify() //打印結果 update
總結:
觀察者模式是由具體目標調度,比如當事件觸發,Dep就會去調用觀察者的方法,所以觀察者的訂閱者和發布者之間是存在依賴的。
發布訂閱模式由統一調度中心調用,因此發布者和訂閱者不需要知道對方的存在。