国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 編程 > JavaScript > 正文

Vue 源碼分析之 Observer實(shí)現(xiàn)過程

2019-11-19 14:05:23
字體:
供稿:網(wǎng)友

導(dǎo)語:

本文是對 Vue 官方文檔深入響應(yīng)式原理(https://cn.vuejs.org/v2/guide/reactivity.html)的理解,并通過源碼還原實(shí)現(xiàn)過程。

響應(yīng)式原理可分為兩步,依賴收集的過程與觸發(fā)-重新渲染的過程。依賴收集的過程,有三個很重要的類,分別是 Watcher、Dep、Observer。本文主要解讀 Observer 。

這篇文章講解上篇文章沒有覆蓋到的 Observer 部分的內(nèi)容,還是先看官網(wǎng)這張圖:

Observer 最主要的作用就是實(shí)現(xiàn)了上圖中touch -Data(getter) - Collect as Dependency這段過程,也就是依賴收集的過程。

還是以下面的代碼為例子進(jìn)行梳理:

(注:左右滑動即可查看完整代碼,下同)

varvm = newVue({el: '#demo',data: {firstName: 'Hello',fullName: ''},watch: {firstName(val) {this.fullName = val + 'TalkingData';},}})

在源碼中,通過還原Vue 進(jìn)行實(shí)例化的過程,從開始一步一步到Observer 類的源碼依次為(省略了很多不在本篇文章討論的代碼):

// src/core/instance/index.jsfunctionVue(options) {if(process.env.NODE_ENV !== 'production'&&!(thisinstanceofVue)) {warn('Vue is a constructor and should be called with the `new` keyword')}this._init(options)}// src/core/instance/init.jsVue.prototype._init = function(options?: Object) {constvm: Component = this// ...initState(vm)// ...}// src/core/instance/state.jsexportfunctioninitState(vm: Component) {// ...constopts = vm.$optionsif(opts.data) {initData(vm)}// ...}functioninitData(vm: Component) {letdata = vm.$options.datadata = vm._data = typeofdata === 'function'? getData(data, vm): data || {}// ...// observe dataobserve(data, true/* asRootData */)}

在initData 方法中,開始了對data 項(xiàng)中的數(shù)據(jù)進(jìn)行“觀察”,會將所有數(shù)據(jù)的變成observable 的。接下來看observe 方法的代碼:

// src/core/observer/index.jsfunctionobserve(value: any, asRootData: ?boolean): Observer| void{// 如果不是對象,直接返回if(!isObject(value) || value instanceofVNode) {return}letob: Observer | voidif(hasOwn(value, '__ob__') && value.__ob__ instanceofObserver) {// 如果有實(shí)例則返回實(shí)例ob = value.__ob__} elseif(// 確保value是單純的對象,而不是函數(shù)或者是Regexp等情況observerState.shouldConvert &&!isServerRendering() &&(Array.isArray(value) || isPlainObject(value)) &&Object.isExtensible(value) &&!value._isVue) {// 實(shí)例化一個 Observerob = newObserver(value)}if(asRootData && ob) {ob.vmCount++}returnob}

observe 方法的作用是給data 創(chuàng)建一個Observer 實(shí)例并返回,如果data 有ob屬性了,說明已經(jīng)有Observer 實(shí)例了,則返回現(xiàn)有的實(shí)例。Vue 的響應(yīng)式數(shù)據(jù)都會有一個ob的屬性,里面存放了該屬性的Observer 實(shí)例,防止重復(fù)綁定。再來看new Observer(value) 過程中發(fā)生了什么:

exportclassObserver{value: any;dep: Dep;vmCount: number; // number of vms that has this object as root $dataconstructor(value: any) {this.value = valuethis.dep = newDep()this.vmCount = 0def(value, '__ob__', this)if(Array.isArray(value)) {// ...this.observeArray(value)} else{this.walk(value)}}walk (obj: Object) {constkeys = Object.keys(obj)for(leti = 0; i < keys.length; i++) {defineReactive(obj, keys[i], obj[keys[i]])}}observeArray (items: Array<any>) {for(leti = 0, l = items.length; i < l; i++) {observe(items[i])}}}

通過源碼可以看到,實(shí)例化Observer 過程中主要是做了兩個判斷。如果是數(shù)組,則對數(shù)組里面的每一項(xiàng)再次調(diào)用oberser 方法進(jìn)行觀察;如果是非數(shù)組的對象,遍歷對象的每一個屬性,對其調(diào)用defineReactive 方法。這里的defineReactive 方法就是核心!通過使用Object.defineProperty 方法對每一個需要被觀察的屬性添加get/set,完成依賴收集。依賴收集過后,每個屬性都會有一個Dep 來保存所有Watcher 對象。按照文章最開始的例子來講,就是對firstName和fullName分別添加了get/set,并且它們各自有一個Dep 實(shí)例來保存各自觀察它們的所有Watcher 對象。下面是defineReactive 的源碼:

exportfunctiondefineReactive(obj: Object,key: string,val: any,customSetter?: ?Function,shallow?: boolean) {constdep = newDep()// 獲取屬性的自身描述符constproperty = Object.getOwnPropertyDeor(obj, key)if(property && property.configurable === false) {return}// cater for pre-defined getter/setters// 檢查屬性之前是否設(shè)置了 getter/setter// 如果設(shè)置了,則在之后的 get/set 方法中執(zhí)行設(shè)置了的 getter/setterconstgetter = property && property.getconstsetter = property && property.set// 通過對屬性再次調(diào)用 observe 方法來判斷是否有子對象// 如果有子對象,對子對象也進(jìn)行依賴搜集letchildOb = !shallow && observe(val)Object.defineProperty(obj, key, {enumerable: true,configurable: true,get: functionreactiveGetter() {// 如果屬性原本擁有g(shù)etter方法則執(zhí)行constvalue = getter ? getter.call(obj) : valif(Dep.target) {// 進(jìn)行依賴收集dep.depend()if(childOb) {// 如果有子對象,對子對象也進(jìn)行依賴搜集childOb.dep.depend()// 如果屬性是數(shù)組,則對每一個項(xiàng)都進(jìn)行依賴收集// 如果某一項(xiàng)還是數(shù)組,則遞歸if(Array.isArray(value)) {dependArray(value)}}}returnvalue},set: functionreactiveSetter(newVal) {// 如果屬性原本擁有g(shù)etter方法則執(zhí)行// 通過getter方法獲取當(dāng)前值,與新值進(jìn)行比較// 如果新舊值一樣則不需要執(zhí)行下面的操作constvalue = getter ? getter.call(obj) : val/* eslint-disable no-self-compare */if(newVal === value || (newVal !== newVal && value !== value)) {return}/* eslint-enable no-self-compare */if(process.env.NODE_ENV !== 'production'&& customSetter) {customSetter()}if(setter) {// 如果屬性原本擁有setter方法則執(zhí)行setter.call(obj, newVal)} else{// 如果原本沒有setter則直接賦新值val = newVal}// 判斷新的值是否有子對象,有的話繼續(xù)觀察子對象childOb = !shallow && observe(newVal)// 通知所有的觀察者,更新狀態(tài)dep.notify()}})}

按照源碼中的中文注釋,應(yīng)該可以明白defineReactive 執(zhí)行的過程中做了哪些工作。其實(shí)整個過程就是遞歸,為每個屬性添加getter/setter。對于getter/setter,同樣也需要對每一個屬性進(jìn)行遞歸(判斷子對象)的完成觀察者模式。對于getter,用來完成依賴收集,即源碼中的dep.depend()。對于setter,一旦一個數(shù)據(jù)觸發(fā)其set方法,便會發(fā)布更新消息,通知這個數(shù)據(jù)的所有觀察者也要發(fā)生改變。即源碼中的dep.notify()。

總結(jié)

以上所述是小編給大家介紹的 Vue 源碼分析之 Observer實(shí)現(xiàn)過程,希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會及時回復(fù)大家的。在此也非常感謝大家對武林網(wǎng)網(wǎng)站的支持!

發(fā)表評論 共有條評論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 北碚区| 磴口县| 纳雍县| 乌兰县| 长宁区| 山东| 丹巴县| 开原市| 榕江县| 奉新县| 鄄城县| 益阳市| 利津县| 榆林市| 子长县| 资中县| 双鸭山市| 阿拉善盟| 太保市| 蒙山县| 平度市| 金坛市| 富民县| 东阿县| 青海省| 滦平县| 黔江区| 玉林市| 茌平县| 六盘水市| 嘉荫县| 青铜峡市| 运城市| 翼城县| 五原县| 黄冈市| 卢龙县| 淮北市| 桐柏县| 栖霞市| 太原市|