摘要:實(shí)現(xiàn)了一個(gè)簡(jiǎn)單的訂閱觀察者類,這個(gè)類被用于在數(shù)據(jù)修改時(shí)通知各個(gè)以觸發(fā)對(duì)應(yīng)的更新,從而實(shí)現(xiàn)數(shù)據(jù)的響應(yīng),這個(gè)會(huì)在后續(xù)的數(shù)據(jù)響應(yīng)化里提到。
observer 實(shí)現(xiàn)了一個(gè)簡(jiǎn)單的訂閱觀察者類,這個(gè)類被用于在數(shù)據(jù)修改時(shí)通知各個(gè) watcher 以觸發(fā)對(duì)應(yīng)的更新,從而實(shí)現(xiàn)數(shù)據(jù)的響應(yīng),這個(gè)會(huì)在后續(xù)的數(shù)據(jù)響應(yīng)化里提到。
src/observer src/observer/dep.js原文地址
項(xiàng)目地址
dep 被 watcher 引用
A dep is an observable that can have multiple
directives subscribing to it.
(dep 是一個(gè)可以被多個(gè)指令訂閱的觀察者)
// 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() } }
代碼量很少,但是幾個(gè)點(diǎn)暫時(shí)不明,一個(gè)是 this.subs.$remove(sub), 貌似是給數(shù)組添加了一個(gè) remove 方法, target 擁有 addDep 方法, subs的 item 擁有 update 方法
更正,dep 類用來(lái)做依賴采集,是一個(gè)簡(jiǎn)單的訂閱-觀察者模式,而 target 和 subs 用于存放 watcher,dep 類用于數(shù)據(jù)響應(yīng)化的實(shí)現(xiàn),在后續(xù)會(huì)講到這個(gè)
src/observer/array.js實(shí)現(xiàn)了 arrayMethods 類,該類繼承了 array 對(duì)象:
... const arrayProto = Array.prototype export const arrayMethods = Object.create(arrayProto) ...
同時(shí)還對(duì) 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 方法的實(shí)現(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ù)組的幾個(gè)原型方法,從而能夠在開發(fā)者操作 data 數(shù)組時(shí),能夠觸發(fā)更新事件: ob.dep.notify()
src/observer/index.jsindex.js 實(shí)現(xiàn)了 Observer 類, 觀察者類綁定了每一個(gè)被觀察的對(duì)象,一旦綁定,Observer 類會(huì)將目標(biāo)對(duì)象的屬性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 實(shí)現(xiàn)在 util/env 中:
export const hasProto = "__proto__" in {}
實(shí)現(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)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://www.ezyhdfw.cn/yun/85216.html
摘要:在學(xué)習(xí)過程中,為加上了中文的注釋,希望可以對(duì)其他想學(xué)習(xí)源碼的小伙伴有所幫助。數(shù)據(jù)綁定原理前面已經(jīng)講過數(shù)據(jù)綁定的原理了,現(xiàn)在從源碼來(lái)看一下數(shù)據(jù)綁定在中是如何實(shí)現(xiàn)的。 寫在前面 因?yàn)閷?duì)Vue.js很感興趣,而且平時(shí)工作的技術(shù)棧也是Vue.js,這幾個(gè)月花了些時(shí)間研究學(xué)習(xí)了一下Vue.js源碼,并做了總結(jié)與輸出。文章的原地址:https://github.com/answershuto/le...
摘要:倡導(dǎo)開發(fā)者盡量不直接操作,但有的時(shí)候由于各種需求讓開發(fā)者不得不這樣做,于是的實(shí)現(xiàn)就是讓開發(fā)者在修改數(shù)據(jù)后,能夠在數(shù)據(jù)更新到后才執(zhí)行對(duì)應(yīng)的函數(shù),從而獲取最新的數(shù)據(jù)。 Vue 倡導(dǎo)開發(fā)者盡量不直接操作 DOM,但有的時(shí)候由于各種需求讓開發(fā)者不得不這樣做,于是 nextTick 的實(shí)現(xiàn)就是讓開發(fā)者在修改數(shù)據(jù)后,能夠在數(shù)據(jù)更新到 DOM 后才執(zhí)行對(duì)應(yīng)的函數(shù),從而獲取最新的 DON 數(shù)據(jù)。 原文...
摘要:所以整個(gè)的核心,就是如何實(shí)現(xiàn)這三樣?xùn)|西以上摘自囧克斯博客的一篇文章從版本開始這個(gè)時(shí)候的項(xiàng)目結(jié)構(gòu)如下源碼在里面,為打包編譯的代碼,為打包后代碼放置的位置,為測(cè)試代碼目錄。節(jié)點(diǎn)類型摘自資源另一位作者關(guān)于源碼解析 本項(xiàng)目的源碼學(xué)習(xí)筆記是基于 Vue 1.0.9 版本的也就是最早的 tag 版本,之所以選擇這個(gè)版本,是因?yàn)檫@個(gè)是最原始沒有太多功能拓展的版本,有利于更好的看到 Vue 最開始的骨...
摘要:現(xiàn)在網(wǎng)上已經(jīng)有大量的源碼分析文章,各種技術(shù)的都有。你完全可以寫成下面的鏈?zhǔn)斤L(fēng)格方法會(huì)最先被執(zhí)行同樣,為了便于理解,我會(huì)借用流里面經(jīng)常用到的水流進(jìn)行類比。該子類的命名是有規(guī)律可言的。現(xiàn)在網(wǎng)上已經(jīng)有大量的源碼分析文章,各種技術(shù)的都有。但我覺得很多文章對(duì)初學(xué)者并不友好,讓人讀起來(lái)云里霧里的,比源碼還源碼。究其原因,是根本沒有從學(xué)習(xí)者的角度去分析。在自己完成了源碼閱讀之后,卻忘記了自己是如何一步步提...
閱讀 2988·2021-11-19 11:35
閱讀 2642·2021-11-02 14:40
閱讀 1477·2021-09-04 16:48
閱讀 3084·2019-08-30 15:55
閱讀 1848·2019-08-30 13:11
閱讀 2014·2019-08-29 11:12
閱讀 1160·2019-08-27 10:52
閱讀 3235·2019-08-26 18:36