最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

打印Proxy對象和ref對象的包實(shí)現(xiàn)詳解

 更新時(shí)間:2022年11月15日 16:24:00   作者:小白不是很聰明  
這篇文章主要為大家介紹了打印Proxy對象和ref對象的包實(shí)現(xiàn)詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪

前因

平時(shí)工作的時(shí)候,我喜歡用console.log調(diào)試大法。但Vue3更新后,控制臺都是打印的Proxy對象和ref對象,想看里邊的值,就需要很麻煩的一層一層的展開。

為了解決這個(gè)問題,我試過在編輯器中寫一個(gè)新的快捷鍵,快速寫出console.log(JSON.parse(JSON.stringify()))。

但我用的是webStorm,它自帶的.log快捷鍵太舒服了,比如這樣:abc.log 點(diǎn)擊tab鍵,就自動(dòng)替換為console.log(abc)。

我試了好久,終究還是沒能拓展類似的代碼。所以才有了重寫console.log()的想法。

目標(biāo)

我希望新的console.log可以像現(xiàn)在的console.log一模一樣,只是當(dāng)打印Proxyref對象時(shí)可以直接輸出它的源對象或ref.value。并且,還保留記錄當(dāng)前文件和行數(shù)的功能,可以讓我看到到底是哪個(gè)文件哪個(gè)步驟執(zhí)行的打印。

結(jié)果

先說結(jié)果:

我翻了好久的文檔,終究還是不能達(dá)到我想要的效果,控制臺右側(cè)展示出的打印文檔及行號終究還是不能直接顯示源文件,如果有大神能看到這篇文章的話,希望告訴我怎么怎么才能實(shí)現(xiàn)這個(gè)想法。

但退而求其次,我用console.traceError.stack兩種方式十分簡陋的完成了這個(gè)目標(biāo)。

各位可以去 下載試試,源碼也就不到200行,有興趣的同學(xué)可以看看。

實(shí)現(xiàn)(直接看源碼的同學(xué)可以略過)

判斷一個(gè)對象是否是Proxy

這個(gè)不好判斷,Vue3添加了isProxy 方法,但如果不是Vue環(huán)境的話,那這個(gè)方法就失效了。 而且就這么一個(gè)簡單的小功能,實(shí)在沒必要依賴其他的包。 最終是選擇在用戶new Proxy之前,把Proxy對象改造。

// 記錄用戶new Proxy操作的所有對象
// WeakSet,WeakMap,都是弱引用,不干預(yù)其他模塊的垃圾回收機(jī)制
export const proxyMap = new WeakMap()
let OriginalProxy = null
export function listenProxy() {
    if (OriginalProxy) { // 防止用戶多次調(diào)用監(jiān)聽
        return
    }
    OriginalProxy = window.Proxy
    window.Proxy = new Proxy(Proxy, {
        construct(target, args) {
            const newProxy = new OriginalProxy(...args)
            proxyInstances.set(newProxy, target)
            return newProxy
        },
        get(obj, prop) {
            // https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Symbol/hasInstance
            if (prop === Symbol.hasInstance) { // 監(jiān)控 `instanceof` 關(guān)鍵字
                return instance => proxyMap.has(instance)
            }
            // https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Reflect/get
            return Reflect.get(...arguments)
        }
    })
}
export function unListenProxy() {
    window.Proxy = OriginalProxy || window.Proxy
}

輸出用戶log的源對象

按說我們上一步已經(jīng)監(jiān)控了用戶動(dòng)作,可以獲取源對象,等用戶log的時(shí)候,我們直接輸出源對象就可以了。但這也有個(gè)問題,Proxy畢竟不是普通的對象,通過Proxy獲取的結(jié)果,很可能跟源對象沒有一毛錢關(guān)系。所以只能通過深克隆返回源對象的值,但這也有個(gè)問題,就是對于某些不能遍歷的對象或?qū)傩?,就打印不了?hellip;…

問題貌似鎖死了,但,我們實(shí)際運(yùn)用中,只是為了簡簡單單輸出一個(gè)不用展開的源對象而已,甚至運(yùn)用場景都特別單一:Vue3! 用戶如果覺得打印的不準(zhǔn)確,換一個(gè)api不完了嗎,比如我們監(jiān)控的是console.log,那用戶就用console.info一樣能輸出相同的結(jié)果。 把選擇權(quán)交給用戶就好了。在引用包的時(shí)候,再寫多一個(gè)配置項(xiàng),讓用戶自己選平時(shí)的使用場景哪個(gè)正確結(jié)果比較多,就選哪個(gè)。想要完全正確,就換一個(gè)其他的api。

我簡直是個(gè)天才,哈哈哈

export function getOrg(obj) {
    return proxyMap.get(obj)
}
// 深克隆
export function clone(obj, _refs = new WeakSet()) {
    if (obj === null || obj === undefined) return null
    if (typeof obj !== 'object') return obj
    if (obj.constructor === Date) return new Date(obj)
    if (obj.constructor === RegExp) return new RegExp(obj)
    const newObj = new obj.constructor() //保持繼承的原型
    for (const key in obj) {
        if (obj.hasOwnProperty(key)) {
            const val = obj[key]
            if (typeof val === 'object' && !_refs.has(val)) {
                newObj[key] = clone(val)
            } else {
                newObj[key] = val
            }
        }
    }
    return newObj
}

最后暴露出去給用戶調(diào)用

import { listenProxy, unListenProxy, clone, getOrg } from "./until";
let config = {
    key: 'log', // any String
    type: 'trace', // 'trace' | 'error' | 'any String'
    cloneProxy: getOrg
}
let Vue = {}
export default function (obj = {}, vue) {
    Vue = vue || {}
    config = { ...config, ...obj }
    if (obj.copy === 'clone') {
        config.cloneProxy = clone
    }
    listenLog(config)
}
// ----------------------------------------
const { groupCollapsed, groupEnd, trace, log } = console
// const type = 'trace' | 'error' | ''
function listenLog() {
    const isRef = Vue.isRef || (obj => {
        return typeof obj === 'object' && !!obj.constructor && obj.constructor.name === 'RefImpl'
    })
    const unref = Vue.unref || (obj => obj.value)
    const { key, type, cloneProxy } = config
    if (!key) {
        console.error('Missing required parameter: key')
    }
    listenProxy() // 為 new Proxy 對象添加 `instanceof` 支持
    console[key] = function (...arr) {
        const newArr = arr.map(i => {
            if (isRef(i)) {
                return unref(i)
            } else if (i instanceof Proxy) {
                return cloneProxy(i)
            } else {
                return i
            }
        })
        groupCollapsed(...newArr)
        // 以 trace
        if (type === 'trace') {
            // trace(...newArr)
            console.log('第二行即為調(diào)用者所在的文件位置')
            trace('The second line is the file location of the caller')
            groupEnd()
            return
        }
        let stack = new Error().stack || ''
        // stack = stack.replace('Error', 'Log')
        if (type === 'error') {
            log('%c這不是一個(gè)錯(cuò)誤,請點(diǎn)擊第二行的"at",跳轉(zhuǎn)到對應(yīng)的文件', 'color: #008000')
            log('%cThis is not an error. Please click "at" in the second line to jump to the corresponding file', 'color: #008000')
            log(stack)
            groupEnd()
            return;
        }
        // 簡單輸入模式,控制臺看起來是簡單了,卻失去了點(diǎn)擊鏈接直接跳轉(zhuǎn)到對應(yīng)文件的功能
        const stackArr = stack.match(/at.*\s/g) || []
        log(stackArr[1])
        groupEnd()
    }
}

至此已全部結(jié)束。

再加上一點(diǎn)ts的解釋文件,那這個(gè)庫就能運(yùn)行在所有平臺了

以上就是打印Proxy對象和ref對象的包實(shí)現(xiàn)詳解的詳細(xì)內(nèi)容,更多關(guān)于打印Proxy ref對象包的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

最新評論

宁都县| 井陉县| 江城| 桦川县| 张家界市| 隆化县| 尚义县| 静安区| 习水县| 张家川| 宕昌县| 基隆市| 镇远县| 湘西| 子长县| 彭山县| 修武县| 巴青县| 江都市| 称多县| 梅州市| 视频| 左贡县| 巧家县| 齐齐哈尔市| 十堰市| 响水县| 凉山| 卢氏县| 大关县| 鞍山市| 绥滨县| 荃湾区| 枞阳县| 博客| 香河县| 辛集市| 红原县| 万源市| 梓潼县| 玉山县|