摘要:實現了一個簡單的訂閱觀察者類,這個類被用于在數據修改時通知各個以觸發對應的更新,從而實現數據的響應,這個會在后續的數據響應化里提到。
observer 實現了一個簡單的訂閱觀察者類,這個類被用于在數據修改時通知各個 watcher 以觸發對應的更新,從而實現數據的響應,這個會在后續的數據響應化里提到。
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), 貌似是給數組添加了一個 remove 方法, target 擁有 addDep 方法, subs的 item 擁有 update 方法
更正,dep 類用來做依賴采集,是一個簡單的訂閱-觀察者模式,而 target 和 subs 用于存放 watcher,dep 類用于數據響應化的實現,在后續會講到這個
src/observer/array.js實現了 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 方法的實現:
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: 避免泄露參數 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 }) })
通過改寫數組的幾個原型方法,從而能夠在開發者操作 data 數組時,能夠觸發更新事件: ob.dep.notify()
src/observer/index.jsindex.js 實現了 Observer 類, 觀察者類綁定了每一個被觀察的對象,一旦綁定,Observer 類會將目標對象的屬性property keys 轉化為 getter/setters, 以收集依賴關系和分派更新
/** * 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) } } ...
從構造函數可以知道之前代碼里一直出現的 _ob_ 屬性就是指 Observer 類
其中 hasProto 實現在 util/env 中:
export const hasProto = "__proto__" in {}
實現的原理是利用 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() } }) }
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/85216.html
摘要:在學習過程中,為加上了中文的注釋,希望可以對其他想學習源碼的小伙伴有所幫助。數據綁定原理前面已經講過數據綁定的原理了,現在從源碼來看一下數據綁定在中是如何實現的。 寫在前面 因為對Vue.js很感興趣,而且平時工作的技術棧也是Vue.js,這幾個月花了些時間研究學習了一下Vue.js源碼,并做了總結與輸出。文章的原地址:https://github.com/answershuto/le...
摘要:倡導開發者盡量不直接操作,但有的時候由于各種需求讓開發者不得不這樣做,于是的實現就是讓開發者在修改數據后,能夠在數據更新到后才執行對應的函數,從而獲取最新的數據。 Vue 倡導開發者盡量不直接操作 DOM,但有的時候由于各種需求讓開發者不得不這樣做,于是 nextTick 的實現就是讓開發者在修改數據后,能夠在數據更新到 DOM 后才執行對應的函數,從而獲取最新的 DON 數據。 原文...
摘要:所以整個的核心,就是如何實現這三樣東西以上摘自囧克斯博客的一篇文章從版本開始這個時候的項目結構如下源碼在里面,為打包編譯的代碼,為打包后代碼放置的位置,為測試代碼目錄。節點類型摘自資源另一位作者關于源碼解析 本項目的源碼學習筆記是基于 Vue 1.0.9 版本的也就是最早的 tag 版本,之所以選擇這個版本,是因為這個是最原始沒有太多功能拓展的版本,有利于更好的看到 Vue 最開始的骨...
摘要:現在網上已經有大量的源碼分析文章,各種技術的都有。你完全可以寫成下面的鏈式風格方法會最先被執行同樣,為了便于理解,我會借用流里面經常用到的水流進行類比。該子類的命名是有規律可言的。現在網上已經有大量的源碼分析文章,各種技術的都有。但我覺得很多文章對初學者并不友好,讓人讀起來云里霧里的,比源碼還源碼。究其原因,是根本沒有從學習者的角度去分析。在自己完成了源碼閱讀之后,卻忘記了自己是如何一步步提...
閱讀 2804·2021-11-19 11:35
閱讀 2582·2021-11-02 14:40
閱讀 1396·2021-09-04 16:48
閱讀 3009·2019-08-30 15:55
閱讀 1753·2019-08-30 13:11
閱讀 1956·2019-08-29 11:12
閱讀 1088·2019-08-27 10:52
閱讀 3157·2019-08-26 18:36