您好,登錄后才能下訂單哦!
本文小編為大家詳細(xì)介紹“如何打印Proxy對(duì)象和ref對(duì)象的包”,內(nèi)容詳細(xì),步驟清晰,細(xì)節(jié)處理妥當(dāng),希望這篇“如何打印Proxy對(duì)象和ref對(duì)象的包”文章能幫助大家解決疑惑,下面跟著小編的思路慢慢深入,一起來(lái)學(xué)習(xí)新知識(shí)吧。
我希望新的console.log可以像現(xiàn)在的console.log一模一樣,只是當(dāng)打印Proxy
和ref
對(duì)象時(shí)可以直接輸出它的源對(duì)象或ref.value。并且,還保留記錄當(dāng)前文件和行數(shù)的功能,可以讓我看到到底是哪個(gè)文件哪個(gè)步驟執(zhí)行的打印。
但退而求其次,我用console.trace
和Error.stack
兩種方式十分簡(jiǎn)陋的完成了這個(gè)目標(biāo)。
這個(gè)不好判斷,Vue3添加了isProxy 方法,但如果不是Vue環(huán)境的話,那這個(gè)方法就失效了。 而且就這么一個(gè)簡(jiǎn)單的小功能,實(shí)在沒(méi)必要依賴其他的包。 最終是選擇在用戶new Proxy之前,把Proxy對(duì)象改造。
// 記錄用戶new Proxy操作的所有對(duì)象 // WeakSet,WeakMap,都是弱引用,不干預(yù)其他模塊的垃圾回收機(jī)制 export const proxyMap = new WeakMap() let OriginalProxy = null export function listenProxy() { if (OriginalProxy) { // 防止用戶多次調(diào)用監(jiān)聽(tīng) 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 }
按說(shuō)我們上一步已經(jīng)監(jiān)控了用戶動(dòng)作,可以獲取源對(duì)象,等用戶log的時(shí)候,我們直接輸出源對(duì)象就可以了。但這也有個(gè)問(wèn)題,Proxy畢竟不是普通的對(duì)象,通過(guò)Proxy獲取的結(jié)果,很可能跟源對(duì)象沒(méi)有一毛錢關(guān)系。所以只能通過(guò)深克隆返回源對(duì)象的值,但這也有個(gè)問(wèn)題,就是對(duì)于某些不能遍歷的對(duì)象或?qū)傩裕痛蛴〔涣肆?amp;hellip;…
問(wèn)題貌似鎖死了,但,我們實(shí)際運(yùn)用中,只是為了簡(jiǎn)簡(jiǎn)單單輸出一個(gè)不用展開(kāi)的源對(duì)象而已,甚至運(yùn)用場(chǎng)景都特別單一:Vue3
! 用戶如果覺(jué)得打印的不準(zhǔn)確,換一個(gè)api不完了嗎,比如我們監(jiān)控的是console.log
,那用戶就用console.info
一樣能輸出相同的結(jié)果。 把選擇權(quán)交給用戶就好了。在引用包的時(shí)候,再寫多一個(gè)配置項(xiàng),讓用戶自己選平時(shí)的使用場(chǎng)景哪個(gè)正確結(jié)果比較多,就選哪個(gè)。想要完全正確,就換一個(gè)其他的api。
我簡(jiǎn)直是個(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 }
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 對(duì)象添加 `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ò)誤,請(qǐng)點(diǎn)擊第二行的"at",跳轉(zhuǎn)到對(duì)應(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; } // 簡(jiǎn)單輸入模式,控制臺(tái)看起來(lái)是簡(jiǎn)單了,卻失去了點(diǎn)擊鏈接直接跳轉(zhuǎn)到對(duì)應(yīng)文件的功能 const stackArr = stack.match(/at.*\s/g) || [] log(stackArr[1]) groupEnd() } }
再加上一點(diǎn)ts的解釋文件,那這個(gè)庫(kù)就能運(yùn)行在所有平臺(tái)了
讀到這里,這篇“如何打印Proxy對(duì)象和ref對(duì)象的包”文章已經(jīng)介紹完畢,想要掌握這篇文章的知識(shí)點(diǎn)還需要大家自己動(dòng)手實(shí)踐使用過(guò)才能領(lǐng)會(huì),如果想了解更多相關(guān)內(nèi)容的文章,歡迎關(guān)注億速云行業(yè)資訊頻道。
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。