二、響應(yīng)式框架基本原理(Proxy部分)

根據(jù)上一節(jié),我們知道了使用defineProperty來(lái)監(jiān)聽(tīng)數(shù)據(jù)的變化。大概知道響應(yīng)式的基本原理。這一節(jié)我們可以通過(guò)另外一種方式來(lái)做,既使用ES Next的新特性-----Proxy做數(shù)據(jù)代理。去實(shí)現(xiàn)數(shù)據(jù)監(jiān)聽(tīng)。

Proxy

Proxy 對(duì)象用于創(chuàng)建一個(gè)對(duì)象的代理,從而實(shí)現(xiàn)基本操作的攔截和自定義(如屬性查找、賦值、枚舉、函數(shù)調(diào)用等)。

語(yǔ)法:
const p = new Proxy(target, handler)
參數(shù):

target ( 要使用 Proxy 包裝的目標(biāo)對(duì)象(可以是任何類型的對(duì)象,包括原生數(shù)組,函數(shù),甚至另一個(gè)代理)。)

handler ( 一個(gè)通常以函數(shù)作為屬性的對(duì)象,各屬性中的函數(shù)分別定義了在執(zhí)行各種操作時(shí)代理 p 的行為。)

handler

handler 對(duì)象是一個(gè)容納一批特定屬性的占位符對(duì)象。它包含有 Proxy 的各個(gè)捕獲器(trap)。
所有的捕捉器是可選的。如果沒(méi)有定義某個(gè)捕捉器,那么就會(huì)保留源對(duì)象的默認(rèn)行為。
捕捉器等更多詳細(xì) 請(qǐng)查看鏈接 Proxy詳細(xì)說(shuō)明

首先我們先嘗試使用Proxy來(lái)完成上一節(jié)代碼的重構(gòu)。

let data = {
    name: 'fzs',
    info: {
        age: 18,
        driving: 2,
        familyTies: {
            maritalStatus: '已婚'
        },
        hobby: ['乒乓球', '游泳']
    },
}
const observe = data => {
    if (!data || Object.prototype.toString.call(data) !== '[object Object]') {
        return
    }
    Object.keys(data).forEach(key => {
        let currentValue = data[key]
        // 事實(shí)上, Proxy也可以對(duì)函數(shù)類型進(jìn)行代理。這里只對(duì)承載數(shù)據(jù)類型的Object進(jìn)行處理。大家了解即可
        if (typeof currentValue === 'object') {
            // 遞歸處理對(duì)象類型,通過(guò)proxy代理
            observe(currentValue)
            data[key] = new Proxy(currentValue, {
                set: (target, property, value, reciver) => {
                    // setter中執(zhí)行各種操作,存儲(chǔ)等
                    console.log('這是賦值操作')
                    if (value === currentValue) {
                        console.log('不需要重新賦值處理')
                        return true
                    }
                    if (property !== 'length') {
                        console.log('數(shù)組只需要執(zhí)行一次賦值操作,因?yàn)閜ush方法會(huì)引起length的變化,觸發(fā)兩次set操作,我們只需要保留一次即可')
                        // 這里進(jìn)行我們數(shù)組的賦值攔截的其他操作
                    }
                    return Reflect.set(target, property, value) //todo 這是賦值操作
                },
            })
        } else {
            Object.defineProperty(data, key, {
                enumerable: false,
                configurable: false,
                get() {
                    console.log(`getting ${key} value now, getting value is:`, currentValue)
                    return currentValue
                },
                set(newValue) {
                    currentValue = newValue
                    console.log(`setting ${key} value now, setting value is`, currentValue)
                }
            })
        }
    })
}
observe(data)
// 對(duì)數(shù)組進(jìn)行如下操作
if (data.info.hobby) {
    data.info.hobby.push('打籃球')
}

觀察輸出我們發(fā)現(xiàn)程序已經(jīng)監(jiān)聽(tīng)到了深層數(shù)據(jù)的變動(dòng)。

簡(jiǎn)單總結(jié)一下:

1.對(duì)于數(shù)據(jù)鍵值類型為基本類型的情況,我們可以繼續(xù)使用Object.defineProperty
2.對(duì)于鍵值為對(duì)象類型的情況,我們可以繼續(xù)遞歸調(diào)用observe方法,并通過(guò)Proxy返回的新對(duì)象對(duì)data[key]重新賦值,這個(gè)新值的gettersetter已經(jīng)被添加了代理。

了解了Proxy實(shí)現(xiàn)之后,我們對(duì)使用Proxy實(shí)現(xiàn)數(shù)據(jù)代理和使用Object.defineProperty實(shí)現(xiàn)數(shù)據(jù)攔截進(jìn)行對(duì)比,可以得出一下 結(jié)論

  • Object.defineProperty不能監(jiān)聽(tīng)數(shù)組的變化,需要對(duì)數(shù)組方法進(jìn)行重寫。
  • Object.defineProperty必須遍歷對(duì)象的每個(gè)屬性,且需要對(duì)嵌套結(jié)構(gòu)進(jìn)行深層遍歷。
  • Proxy 的代理是針對(duì)整個(gè)對(duì)象的,而不是針對(duì) 對(duì)象 的某個(gè)屬性。因此不像Object.defineProperty必須遍歷對(duì)象的每個(gè)屬性,Proxy只需要做一層代理就可以監(jiān)聽(tīng)同級(jí)結(jié)構(gòu)下的所有屬性變化。當(dāng)然對(duì)于深層結(jié)構(gòu),遞歸還是需要進(jìn)行的。
  • Proxy支持代理數(shù)組的變化。
  • Proxy 的第二個(gè)參數(shù)除了可以使用 set 和 get, 還可以使用13種攔截方法,比Object.defineProperty更強(qiáng)大。 Proxy詳細(xì)說(shuō)明
  • 使用Proxy時(shí),性能將會(huì)被底層持續(xù)優(yōu)化;而使用Object.defineProperty時(shí),性能已經(jīng)不再是優(yōu)化重點(diǎn)。
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容