摘要:實現(xiàn)了一個簡單的訂閱觀察者類,這個類被用于在數(shù)據(jù)修改時通知各個以觸發(fā)對應(yīng)的更新,從而實現(xiàn)數(shù)據(jù)的響應(yīng),這個會在后續(xù)的數(shù)據(jù)響應(yīng)化里提到。
observer 實現(xiàn)了一個簡單的訂閱觀察者類,這個類被用于在數(shù)據(jù)修改時通知各個 watcher 以觸發(fā)對應(yīng)的更新,從而實現(xiàn)數(shù)據(jù)的響應(yīng),這個會在后續(xù)的數(shù)據(jù)響應(yīng)化里提到。
src/observer src/observer/dep.js原文地址
項目地址
dep 被 watcher 引用
A dep is an observable that can have multiple
directives subscribing to it.
(dep 是一個可以被多個指令訂閱的觀察者)
// src/observer/dep.js import { toArray } from "../util/index" let uid = 0 export default function Dep () { this.id = uid++ this.subs = [] } Dep.target = null Dep.prototype.addSub = function (sub) { this.subs.push(sub) } Dep.prototype.removeSub = function (sub) { this.subs.$remove(sub) } Dep.prototype.depend = function () { Dep.target.addDep(this) } Dep.prototype.notify = function () { var subs = toArray(this.subs) for (var i = 0, l = subs.length; i < l; i++) { subs[i].update() } }
代碼量很少,但是幾個點暫時不明,一個是 this.subs.$remove(sub), 貌似是給數(shù)組添加了一個 remove 方法, target 擁有 addDep 方法, subs的 item 擁有 update 方法
更正,dep 類用來做依賴采集,是一個簡單的訂閱-觀察者模式,而 target 和 subs 用于存放 watcher,dep 類用于數(shù)據(jù)響應(yīng)化的實現(xiàn),在后續(xù)會講到這個
src/observer/array.js實現(xiàn)了 arrayMethods 類,該類繼承了 array 對象:
... const arrayProto = Array.prototype export const arrayMethods = Object.create(arrayProto) ...
同時還對 array 拓展了 $set $remove 方法, 這就是在 dep.js 里使用到的 $remove 方法
def( arrayProto, "$set", function $set (index, val) { if (index >= this.length) { this.length = index + 1 } return this.splice(index, 1, val)[0] } ) def( arrayProto, "$remove", function $remove (item) { /* istanbul ignore if */ if (!this.length) return var index = indexOf(this, item) if (index > -1) { return this.splice(index, 1) } } )
def 方法的實現(xiàn):
export function def (obj, key, val, enumerable) { Object.defineProperty(obj, key, { value: val, enumerable: !!enumerable, writable: true, configurable: true }) }
除此之外, arrayMethods 重寫了
"push", "pop", "shift", "unshift", "splice", "sort", "reverse"
這些原型方法:
;[ "push", "pop", "shift", "unshift", "splice", "sort", "reverse" ] .forEach(function (method) { // cache original method var original = arrayProto[method] def(arrayMethods, method, function mutator () { // avoid leaking arguments: 避免泄露參數(shù) arguments // http://jsperf.com/closure-with-arguments var i = arguments.length var args = new Array(i) while (i--) { args[i] = arguments[i] } var result = original.apply(this, args) var ob = this.__ob__ var inserted switch (method) { case "push": inserted = args break case "unshift": inserted = args break case "splice": inserted = args.slice(2) break } if (inserted) ob.observeArray(inserted) // notify change ob.dep.notify() return result }) })
通過改寫數(shù)組的幾個原型方法,從而能夠在開發(fā)者操作 data 數(shù)組時,能夠觸發(fā)更新事件: ob.dep.notify()
src/observer/index.jsindex.js 實現(xiàn)了 Observer 類, 觀察者類綁定了每一個被觀察的對象,一旦綁定,Observer 類會將目標對象的屬性property keys 轉(zhuǎn)化為 getter/setters, 以收集依賴關(guān)系和分派更新
/** * Observer class that are attached to each observed * object. Once attached, the observer converts target * object"s property keys into getter/setters that * collect dependencies and dispatches updates. * * @param {Array|Object} value * @constructor */ export function Observer (value) { this.value = value this.dep = new Dep() def(value, "__ob__", this) if (isArray(value)) { var augment = hasProto ? protoAugment : copyAugment augment(value, arrayMethods, arrayKeys) this.observeArray(value) } else { this.walk(value) } } ...
從構(gòu)造函數(shù)可以知道之前代碼里一直出現(xiàn)的 _ob_ 屬性就是指 Observer 類
其中 hasProto 實現(xiàn)在 util/env 中:
export const hasProto = "__proto__" in {}
實現(xiàn)的原理是利用 Object 的 Geeter 和 Setter:
/** * Define a reactive property on an Object. * * @param {Object} obj * @param {String} key * @param {*} val */ export function defineReactive (obj, key, val) { var dep = new Dep() // cater for pre-defined getter/setters var getter, setter if (config.convertAllProperties) { var property = Object.getOwnPropertyDescriptor(obj, key) if (property && property.configurable === false) { return } getter = property && property.get setter = property && property.set } var childOb = observe(val) Object.defineProperty(obj, key, { enumerable: true, configurable: true, get: function reactiveGetter () { var value = getter ? getter.call(obj) : val if (Dep.target) { dep.depend() if (childOb) { childOb.dep.depend() } if (isArray(value)) { for (var e, i = 0, l = value.length; i < l; i++) { e = value[i] e && e.__ob__ && e.__ob__.dep.depend() } } } return value }, set: function reactiveSetter (newVal) { var value = getter ? getter.call(obj) : val if (newVal === value) { return } if (setter) { setter.call(obj, newVal) } else { val = newVal } childOb = observe(newVal) dep.notify() } }) }
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/85216.html
摘要:在學(xué)習(xí)過程中,為加上了中文的注釋,希望可以對其他想學(xué)習(xí)源碼的小伙伴有所幫助。數(shù)據(jù)綁定原理前面已經(jīng)講過數(shù)據(jù)綁定的原理了,現(xiàn)在從源碼來看一下數(shù)據(jù)綁定在中是如何實現(xiàn)的。 寫在前面 因為對Vue.js很感興趣,而且平時工作的技術(shù)棧也是Vue.js,這幾個月花了些時間研究學(xué)習(xí)了一下Vue.js源碼,并做了總結(jié)與輸出。文章的原地址:https://github.com/answershuto/le...
摘要:倡導(dǎo)開發(fā)者盡量不直接操作,但有的時候由于各種需求讓開發(fā)者不得不這樣做,于是的實現(xiàn)就是讓開發(fā)者在修改數(shù)據(jù)后,能夠在數(shù)據(jù)更新到后才執(zhí)行對應(yīng)的函數(shù),從而獲取最新的數(shù)據(jù)。 Vue 倡導(dǎo)開發(fā)者盡量不直接操作 DOM,但有的時候由于各種需求讓開發(fā)者不得不這樣做,于是 nextTick 的實現(xiàn)就是讓開發(fā)者在修改數(shù)據(jù)后,能夠在數(shù)據(jù)更新到 DOM 后才執(zhí)行對應(yīng)的函數(shù),從而獲取最新的 DON 數(shù)據(jù)。 原文...
摘要:所以整個的核心,就是如何實現(xiàn)這三樣?xùn)|西以上摘自囧克斯博客的一篇文章從版本開始這個時候的項目結(jié)構(gòu)如下源碼在里面,為打包編譯的代碼,為打包后代碼放置的位置,為測試代碼目錄。節(jié)點類型摘自資源另一位作者關(guān)于源碼解析 本項目的源碼學(xué)習(xí)筆記是基于 Vue 1.0.9 版本的也就是最早的 tag 版本,之所以選擇這個版本,是因為這個是最原始沒有太多功能拓展的版本,有利于更好的看到 Vue 最開始的骨...
摘要:現(xiàn)在網(wǎng)上已經(jīng)有大量的源碼分析文章,各種技術(shù)的都有。你完全可以寫成下面的鏈式風(fēng)格方法會最先被執(zhí)行同樣,為了便于理解,我會借用流里面經(jīng)常用到的水流進行類比。該子類的命名是有規(guī)律可言的?,F(xiàn)在網(wǎng)上已經(jīng)有大量的源碼分析文章,各種技術(shù)的都有。但我覺得很多文章對初學(xué)者并不友好,讓人讀起來云里霧里的,比源碼還源碼。究其原因,是根本沒有從學(xué)習(xí)者的角度去分析。在自己完成了源碼閱讀之后,卻忘記了自己是如何一步步提...
閱讀 2844·2021-11-19 11:35
閱讀 2591·2021-11-02 14:40
閱讀 1413·2021-09-04 16:48
閱讀 3019·2019-08-30 15:55
閱讀 1773·2019-08-30 13:11
閱讀 1965·2019-08-29 11:12
閱讀 1102·2019-08-27 10:52
閱讀 3169·2019-08-26 18:36