如何打印Proxy对象和ref对象的包
导读:本文共3172字符,通常情况下阅读需要11分钟。同时您也可以点击右侧朗读,来听本文内容。按键盘←(左) →(右) 方向键可以翻页。
摘要:本文小编为大家详细介绍“如何打印Proxy对象和ref对象的包”,内容详细,步骤清晰,细节处理妥当,希望这篇“如何打印Proxy对象和ref对象的包”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧。目标我希望新的console.log可以像现在的console.log一模一样,只是当打印Proxy和ref对象时可以直接输出它的源对象或ref.value。并且,还保留记录当前... ...
目录
(为您整理了一些要点),点击可以直达。本文小编为大家详细介绍“如何打印Proxy对象和ref对象的包”,内容详细,步骤清晰,细节处理妥当,希望这篇“如何打印Proxy对象和ref对象的包”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧。
目标
我希望新的console.log可以像现在的console.log一模一样,只是当打印Proxy
和ref
对象时可以直接输出它的源对象或ref.value。并且,还保留记录当前文件和行数的功能,可以让我看到到底是哪个文件哪个步骤执行的打印。
结果
但退而求其次,我用console.trace
和Error.stack
两种方式十分简陋的完成了这个目标。
实现(直接看源码的同学可以略过)
判断一个对象是否是Proxy
这个不好判断,Vue3添加了isProxy 方法,但如果不是Vue环境的话,那这个方法就失效了。 而且就这么一个简单的小功能,实在没必要依赖其他的包。 最终是选择在用户new Proxy之前,把Proxy对象改造。
//记录用户newProxy操作的所有对象//WeakSet,WeakMap,都是弱引用,不干预其他模块的垃圾回收机制exportconstproxyMap=newWeakMap()letOriginalProxy=nullexportfunctionlistenProxy(){if(OriginalProxy){//防止用户多次调用监听return}OriginalProxy=window.Proxywindow.Proxy=newProxy(Proxy,{construct(target,args){constnewProxy=newOriginalProxy(...args)proxyInstances.set(newProxy,target)returnnewProxy},get(obj,prop){//https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Symbol/hasInstanceif(prop===Symbol.hasInstance){//监控`instanceof`关键字returninstance=>proxyMap.has(instance)}//https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Reflect/getreturnReflect.get(...arguments)}})}exportfunctionunListenProxy(){window.Proxy=OriginalProxy||window.Proxy}
输出用户log的源对象
按说我们上一步已经监控了用户动作,可以获取源对象,等用户log的时候,我们直接输出源对象就可以了。但这也有个问题,Proxy毕竟不是普通的对象,通过Proxy获取的结果,很可能跟源对象没有一毛钱关系。所以只能通过深克隆返回源对象的值,但这也有个问题,就是对于某些不能遍历的对象或属性,就打印不了了……
问题貌似锁死了,但,我们实际运用中,只是为了简简单单输出一个不用展开的源对象而已,甚至运用场景都特别单一:Vue3
! 用户如果觉得打印的不准确,换一个api不完了吗,比如我们监控的是console.log
,那用户就用console.info
一样能输出相同的结果。 把选择权交给用户就好了。在引用包的时候,再写多一个配置项,让用户自己选平时的使用场景哪个正确结果比较多,就选哪个。想要完全正确,就换一个其他的api。
我简直是个天才,哈哈哈
exportfunctiongetOrg(obj){returnproxyMap.get(obj)}//深克隆exportfunctionclone(obj,_refs=newWeakSet()){if(obj===null||obj===undefined)returnnullif(typeofobj!=='object')returnobjif(obj.constructor===Date)returnnewDate(obj)if(obj.constructor===RegExp)returnnewRegExp(obj)constnewObj=newobj.constructor()//保持继承的原型for(constkeyinobj){if(obj.hasOwnProperty(key)){constval=obj[key]if(typeofval==='object'&&!_refs.has(val)){newObj[key]=clone(val)}else{newObj[key]=val}}}returnnewObj}
最后暴露出去给用户调用
import{listenProxy,unListenProxy,clone,getOrg}from"./until";letconfig={key:'log',//anyStringtype:'trace',//'trace'|'error'|'anyString'cloneProxy:getOrg}letVue={}exportdefaultfunction(obj={},vue){Vue=vue||{}config={...config,...obj}if(obj.copy==='clone'){config.cloneProxy=clone}listenLog(config)}//----------------------------------------const{groupCollapsed,groupEnd,trace,log}=console//consttype='trace'|'error'|''functionlistenLog(){constisRef=Vue.isRef||(obj=>{returntypeofobj==='object'&&!!obj.constructor&&obj.constructor.name==='RefImpl'})constunref=Vue.unref||(obj=>obj.value)const{key,type,cloneProxy}=configif(!key){console.error('Missingrequiredparameter:key')}listenProxy()//为newProxy对象添加`instanceof`支持console[key]=function(...arr){constnewArr=arr.map(i=>{if(isRef(i)){returnunref(i)}elseif(iinstanceofProxy){returncloneProxy(i)}else{returni}})groupCollapsed(...newArr)//以traceif(type==='trace'){//trace(...newArr)console.log('第二行即为调用者所在的文件位置')trace('Thesecondlineisthefilelocationofthecaller')groupEnd()return}letstack=newError().stack||''//stack=stack.replace('Error','Log')if(type==='error'){log('%c这不是一个错误,请点击第二行的"at",跳转到对应的文件','color:#008000')log('%cThisisnotanerror.Pleaseclick"at"inthesecondlinetojumptothecorrespondingfile','color:#008000')log(stack)groupEnd()return;}//简单输入模式,控制台看起来是简单了,却失去了点击链接直接跳转到对应文件的功能conststackArr=stack.match(/at.*\s/g)||[]log(stackArr[1])groupEnd()}}
再加上一点ts的解释文件,那这个库就能运行在所有平台了
读到这里,这篇“如何打印Proxy对象和ref对象的包”文章已经介绍完毕,想要掌握这篇文章的知识点还需要大家自己动手实践使用过才能领会,如果想了解更多相关内容的文章,欢迎关注亿速云行业资讯频道。
如何打印Proxy对象和ref对象的包的详细内容,希望对您有所帮助,信息来源于网络。