vue[源码]你不知道的observe!
生活随笔
收集整理的這篇文章主要介紹了
vue[源码]你不知道的observe!
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
observe工廠函數
在之前的源碼initdata函數中最后一句
observe(data, true /* asRootData */)復制代碼調用了observe函數觀察數據
export function observe (value: any, asRootData: ?boolean): Observer | void { if (!isObject(value) || value instanceof VNode) { return //判斷是否是一個對象或者VNode }let ob: Observer | void //定義變量ob 保存observe實例 if (hasOwn(value, '__ob__') && value.__ob__ instanceof Observer) { ob = value.__ob__ //檢測目標對象是否含有_ob_,并且 __ob__ 屬性應該是Observer的實例 作用是為了避免重復觀察同一個數據對象} else if (//對數據對象進行觀測 shouldObserve && !isServerRendering() && (Array.isArray(value) || isPlainObject(value)) && Object.isExtensible(value) && !value._isVue ) { ob = new Observer(value) } if (asRootData && ob) { ob.vmCount++ } return ob }復制代碼看下else..if..第一個條件shouldObserve 必須為true
export let shouldObserve: boolean = true //初始化默認設置為true export function toggleObserving (value: boolean) {// 接收一個布爾值 改變true false shouldObserve = value}復制代碼第二個條件!isServerRendering() 必須ture
let _isServer //定義一個變量 export const isServerRendering = () => {if (_isServer === undefined) {/* istanbul ignore if */ if (!inBrowser && !inWeex && typeof global !== 'undefined') { // detect presence of vue-server-renderer and avoid // Webpack shimming the process _isServer = global['process'] && global['process'].env.VUE_ENV === 'server' } else { _isServer = false } } return _isServer}復制代碼這個函數作用是為了判斷是否為服務端渲染
第三個條件判斷是否為數組和純對象
第四個判斷對象是可拓展性的...接下來就不說了 相信應該能看懂
ob = new Observer(value)復制代碼最后創建一個observer實例
observe構造函數
walk 實例對象方法遍歷了變量獲得了可枚舉的屬性,
每個屬性調用了defineReactive函數:
export function defineReactive ( obj: Object,key: string,val: any, customSetter?: ?Function, shallow?: boolean) {const dep = new Dep() //定義一個dep常量接收Dep實例對象 //getOwnPropertyDescriptor方法返回指定對象上一個自有屬性對應的屬性描述const property = Object.getOwnPropertyDescriptor(obj, key) if (property && property.configurable === false) {return //判斷是否可配置 }// cater for pre-defined getter/setters const getter = property && property.get //保存 property 對象的 get 和 set函數 const setter = property && property.set if ((!getter || setter) && arguments.length === 2) {val = obj[key]//當只傳遞兩個參數時,說明沒有傳遞第三個參數 val, 那么此時需要根據 key 主動去對象上獲取相應的值,即執行 if 語句塊內的代碼:val = obj[key] }let childOb = !shallow && observe(val) Object.defineProperty(obj, key, { //函數重新定義屬性的 setter/getter,這會導致屬性原有的 set 和 get 方法被覆蓋, 所以要將屬性原有的 setter/getter 緩存,并在重新定義的 set 和 get 方法中調用緩存的函數, 從而做到不影響屬性的原有讀寫操作。 enumerable: true, configurable: true, get: function reactiveGetter () {const value = getter ? getter.call(obj) : val //判斷是否存在getter?直接調用該函數:使用val if (Dep.target) { //Dep.target 中保存的值就是要被收集的依賴(觀察者)dep.depend() //行 dep 對象的 depend 方法將依賴收集到 dep中 if (childOb) { //大概意思是收集的依賴的觸發時機是在使用 $set 或 Vue.set 給數據對象添加新屬性時觸發 childOb.dep.depend() if (Array.isArray(value)) {//對數組依賴收集的處理 dependArray(value) } } }return value }, set: function reactiveSetter (newVal) {const value = getter ? getter.call(obj) : val //如上一樣 /* eslint-disable no-self-compare */ if (newVal === value || (newVal !== newVal && value !== value)) { return //新舊值判斷處理 后面判斷應該是為了處理NaN } /* eslint-enable no-self-compare */ if (process.env.NODE_ENV !== 'production' && customSetter) { customSetter()//環境判斷和customSetter函數判斷(作用:用來打印輔助屬性) } // #7981: for accessor properties without setter if (getter && !setter) return if (setter) {//正確設置屬性值 setter.call(obj, newVal) } else { val = newVal } childOb = !shallow && observe(newVal) dep.notify()//深度觀測 依賴收集 } }) }復制代碼defineReactive 函數的核心就是 將數據對象的數據屬性轉換為訪問器屬性,即為數據對象的屬性設置一對 getter/setter,但其中做了很多處理邊界條件的工作defineReactive 接收五個參數,但是在 walk 方法中調用 defineReactive 函數時只傳遞了前兩個參數,即數據對象和屬性的鍵名
轉載于:https://juejin.im/post/5ca5b4555188251041397735
總結
以上是生活随笔為你收集整理的vue[源码]你不知道的observe!的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: bug修复录-qq浏览器中post请求时
- 下一篇: 微软Skype突破!视讯人数上限来到50