Vue応答式の原理と簡単な実現
5852 ワード
vue原理では,データの観測,依存収集,ビューの更新をどのように実現するかが最も重要である.本稿ではObserver,Dep,Watcherの3つの簡単な実装について述べる.pub(publish)はパブリッシャー、sub(subscribe)はサブスクライバ、cb(callback)はコールバック関数を表します.この話が役に立つと思ったら、starを注文してください.
observerの実装
Observerの役割は簡単に言えばobjectオブジェクトの属性をすべてObjectにすることである.defineProperty()を定義することで、objectの属性を取得したり、属性を変更したりすると、get,setをトリガーしてデータの観測効果を達成することができます.
defineReactiveの役割はオブジェクトの属性に対して簡単なデータ観測を行い、値が取得または設定されるといくつかの行為をトリガする.1つのオブジェクトの属性がオブジェクトである可能性があるため、ここではobserve関数を追加して値を遍歴し、1つのオブジェクトの属性の属性が観測できるようにします.簡単に言えば、すべての属性を無視できるようにすることです.もちろん実際の状況では,配列の状況も考慮する必要があるが,いずれも大同小異である.このようにコードを作るのは少し醜いようで、私たちは属性を設定してsetをトリガしてconsoleが発生します.log()関数は、通知の変化をよりスマートに実現する方法はありませんか.ここではメッセージ購読器で実現する必要があります.これによりconsoleを観察する必要はありません.log()出力の値を見て行う場合,setメソッドに通知を加えるだけで,値が変化すると外値が変化したことを通知する.
Depの実装:
Depの役割は属性値の変化を収集し,setメソッドがトリガーされるとビューを更新することである.では、収集のために配列を用意しましょう.次はDepの実装です.
以上はDepの簡単な実装であり、addSubの役割はサブスクライバを増やすことであり、多くのサブスクライバがあるため、私たちは1つの配列でそれを格納する必要があります.notify()関数の役割はsetが発生したときに通知することです.update()という関数はwatcherで説明します.Depが実現したらset()関数を変更するべきではないでしょうか.次はdefineReactive()修正後のコードです.
setがトリガーされるとdep.notify()が呼び出され、notifyの役割はサブスクライバの遍歴を更新することである.
Watcherのシンプルな実装:
watcherの役割は、状態が変化したときにビューを更新することです.
Watcherの簡単な実装が完了しました.Dep()コンストラクション関数ではsub.update()という行のコードを使用していますが、update関数はWatcherの中の方法で、各subがWathcerの例であることを説明しています.問題はaddSub()という方法で、Watcherをsubsという配列にどのように加えて心を込めて記憶すべきかです.答えはdefineReactive()で修正します
これでDepにWatcherを入れることができたのではないでしょうか.vueソースコードの中ではこれよりずっと複雑で、いろいろなパラメータがあり、頭が大きいのを見ています.本文の目的は、内部原理を簡単に理解させることであり、より深く理解する必要がある場合はソースコードを読む必要があります.
observerの実装
Observerの役割は簡単に言えばobjectオブジェクトの属性をすべてObjectにすることである.defineProperty()を定義することで、objectの属性を取得したり、属性を変更したりすると、get,setをトリガーしてデータの観測効果を達成することができます.
class Observer {
constructor(value) {
this.value = value
this.walk(this.value)
}
walk (value) {
// value
Object.keys(value).forEach((key) = > {
defineReactive(value, key, value[key])
})
}
}
function defineReactive(obj, key ,val) {
let childOb = observe(val)
Obeject.defineProperty(obj, key, {
enumerable: true,
configurable: true,
get() {
console.log('')
return val
},
set(newVal) {
console.log('')
val = newVal
childOb = observe(val)
}
})
}
function observe (value) {
if (typeof value === 'object' && !Array.isArray(value)) {
value = new Observer(value)
}
}
defineReactiveの役割はオブジェクトの属性に対して簡単なデータ観測を行い、値が取得または設定されるといくつかの行為をトリガする.1つのオブジェクトの属性がオブジェクトである可能性があるため、ここではobserve関数を追加して値を遍歴し、1つのオブジェクトの属性の属性が観測できるようにします.簡単に言えば、すべての属性を無視できるようにすることです.もちろん実際の状況では,配列の状況も考慮する必要があるが,いずれも大同小異である.このようにコードを作るのは少し醜いようで、私たちは属性を設定してsetをトリガしてconsoleが発生します.log()関数は、通知の変化をよりスマートに実現する方法はありませんか.ここではメッセージ購読器で実現する必要があります.これによりconsoleを観察する必要はありません.log()出力の値を見て行う場合,setメソッドに通知を加えるだけで,値が変化すると外値が変化したことを通知する.
Depの実装:
Depの役割は属性値の変化を収集し,setメソッドがトリガーされるとビューを更新することである.では、収集のために配列を用意しましょう.次はDepの実装です.
class Dep {
constructor() {
this.subs = []
}
addSub (sub) {
this.subs.push(sub)
}
notify () {
const subs = this.subs.slice()
subs.forEach((sub) => {
sub.update() //
})
}
}
以上はDepの簡単な実装であり、addSubの役割はサブスクライバを増やすことであり、多くのサブスクライバがあるため、私たちは1つの配列でそれを格納する必要があります.notify()関数の役割はsetが発生したときに通知することです.update()という関数はwatcherで説明します.Depが実現したらset()関数を変更するべきではないでしょうか.次はdefineReactive()修正後のコードです.
function defineReactive(obj, key ,val) {
let dep = new Dep() // Dep
let childOb = observe(val)
Obeject.defineProperty(obj, key, {
enumerable: true,
configurable: true,
get() {
return val
},
set(newVal) {
val = newVal
childOb = observe(val)
dep.notify() // , Dep
}
})
}
setがトリガーされるとdep.notify()が呼び出され、notifyの役割はサブスクライバの遍歴を更新することである.
Watcherのシンプルな実装:
watcherの役割は、状態が変化したときにビューを更新することです.
class Watcher {
constructor (vm, cb, expOrFn) {
this.vm = vm // Vue
this.cb = cb
// expOrFn
// ,
this.getter = expOrFn
this.value = this.get()
}
get () {
Dep.target = this
const vm = this.vm
value = this.getter.call(this.vm, vm)
Dep.target = null
return value
}
update () {
this.run()
}
run () {
const value = this.get()
if (value !== this.value) {
const oldValue = this.value
this.value = value
this.cb.call(this.vm, value, oldValue)
}
}
}
Watcherの簡単な実装が完了しました.Dep()コンストラクション関数ではsub.update()という行のコードを使用していますが、update関数はWatcherの中の方法で、各subがWathcerの例であることを説明しています.問題はaddSub()という方法で、Watcherをsubsという配列にどのように加えて心を込めて記憶すべきかです.答えはdefineReactive()で修正します
function defineReactive(obj, key ,val) {
let dep = new Dep() // Dep
let childOb = observe(val)
Obeject.defineProperty(obj, key, {
enumerable: true,
configurable: true,
get() {
if(Dep.target) {
dep.addSub(Dep.target)
}
return val
},
set(newVal) {
val = newVal
childOb = observe(val)
dep.notify() // , Dep
}
})
}
これでDepにWatcherを入れることができたのではないでしょうか.vueソースコードの中ではこれよりずっと複雑で、いろいろなパラメータがあり、頭が大きいのを見ています.本文の目的は、内部原理を簡単に理解させることであり、より深く理解する必要がある場合はソースコードを読む必要があります.