函数劫持能做啥?前端黑科技揭秘
栏目: JavaScript · 发布时间: 5年前
内容简介:啥是函数劫持?其实就是给调用的函数加一层包装函数,在包装函数里调用一下原函数,有点像代理服务器的作用, 拦截一些全局对象和方法, 能实现一些非常便利的全局功能,今天我就抛砖引玉跟大家分享一下。前段时间看到emoji图标在地址栏的动画应用,挺有趣的,很娱乐,我就试着能不能把emoji应用于到我正在研究的函数劫持的实例中,实际做了一下效果还不错,自娱自乐一下,也分享给大家使用,给平淡的开发生活添加一抹亮色。console.log本身支持样表式,第一个参数中加入 %c格式化输出,第二个参数就可以传入样式表了,可以
啥是函数劫持?其实就是给调用的函数加一层包装函数,在包装函数里调用一下原函数,有点像代理服务器的作用, 拦截一些全局对象和方法, 能实现一些非常便利的全局功能,今天我就抛砖引玉跟大家分享一下。
人生苦短,苦中做乐的console.log 美化
前段时间看到emoji图标在地址栏的动画应用,挺有趣的,很娱乐,我就试着能不能把emoji应用于到我正在研究的函数劫持的实例中,实际做了一下效果还不错,自娱自乐一下,也分享给大家使用,给平淡的开发生活添加一抹亮色。
console.log本身支持样表式,第一个参数中加入 %c格式化输出,第二个参数就可以传入样式表了,可以实现渐变色,显示图片等非常漂亮的效果。 能不能让console.log 默认就改变颜色呢,我们试着劫持 console.log 给它添加默认功能 ,让它每次都随机更换一种颜色和图标进行输出,为了保护视力,增大一号字体,效果如下:
var _consoleLog=window.console.log; window.console.log=function (){ if(arguments.length==1 && typeof arguments[0]!="object"){ var iconList=[":earth_asia:",":first_quarter_moon_with_face:",":star2:",":fire:",":bird:",":imp:",":jack_o_lantern:",":confetti_ball:",":tanabata_tree:",":gift:",":four_leaf_clover:",":tulip:",":seedling:",":maple_leaf:",":cherry_blossom:",":leaves:",":herb:",":cherries:",":apple:",":tangerine:",":strawberry:",":pineapple:",":grapes:"] var colorList=["background-color:#8BC34A;color:white", "background-color:#42b983;color:white", "background-color:#33A5FF;color:white", "background-color:orange;color:white", "background-color:#2EAFB0;color:white", "background-color:#6EC1C2;color:white", "background-color:#FFDD4D;color:black", "background-color:#7F2B82;color:white", "background-color:#4b4b4b;color:white", "background-color:#E41A6A;color:white"] var idx1=Math.floor(Math.random()*iconList.length); var idx2=Math.floor(Math.random()*colorList.length); var msg=arguments[0]; msg="%c "+iconList[idx1]+" "+msg; _consoleLog(msg,"font-size:20pt;"+colorList[idx2]) }else{ _consoleLog.apply(this,arguments) } } console.log("hello,world") 复制代码
在公共代码里引入一下,每天就可以看到五彩缤纷的console输出了。注:win 7及以下操作系统不支持emoji表情的颜色显示
防眼花的方法:json输出自动格式化
JSON.stringify会把JSON输出成一行,非常难看,有没有方法美化一下呢,我们来看下mdn文档: JSON.stringify有3个参数,第3个参数可以指定缩进用的空白字符串,用于美化输出(pretty-print);如果参数是个数字,它代表有多少的空格;上限为10。该值若小于1,则意味着没有空格;如果该参数为字符串(字符串的前十个字母),该字符串将被作为空格;那么第二个参数用来干嘛呢,原来是一个回调函数可以用于过滤每一个属性值,一般用不到传null就好了,
JSON.stringify({result:{a:1,b:2}},null,4) 复制代码
输出结果已经是格式化好的json了, 完美:
{ "result": { "a": 1, "b": 2 } } 复制代码
但是每次调用都传3个参数太烦了,何况还有很多同学不知道这种用法,我们尝试用函数劫持封装一下,这样就默认带格式化了:
var _stringify=JSON.stringify JSON.stringify=function (){ if(arguments.length==1){ return _stringify(arguments[0],null,4) }else{ return _stringify.apply(this,arguments) } } 复制代码
再来试试JSON.stringify吧,不用传3个参数也能格式化输出了。需要注意的是不要重复执行函数劫持,否则会产生递归死循环。那么怎么判断已经劫持过了呢,调用一下函数的toString方法,如果是原生的函数,会返回 [native code] ,如下
"function stringify() { [native code] }" 复制代码
做一下字符检测就可以了。
未雨绸繆,防手贱执行alert
有些新手喜欢用alert 调试,这种代码如果带到线上简直是灾难,我们写个劫持,永远杜绝这个问题:
window.alert=function (){ console.log(arguments[0]) } 复制代码
再也弹不出的alert,你还好吗........
真正的黑科技1:mock.js 瞒天过海拦截ajax请求
压轴戏来了,在前后端分离的开发流程中,不可避免要用到mock数据,常见的有两种方案。
- 客户端mock,好处是不用搭建服务器,在前端就把请求拦截下来。
- 服务端mock,就是做一个空接口,返回死数据。比较接近于真实环境的http交互流程。
我自己在多年前就实现了mockjs类似的功能,后来才发现有这样一个开源项目,也算白白做了一个轮子吧。它的原理还是函数劫持,劫持window.XMLHttpRequest对象,主要是对send方法和onreadystatechange事件的劫持,劫持send简单,和前面的console.log劫持一毛一样,嵌套个高阶函数封装一下就完事了,可是事件要怎么代理,谢天谢地的是XHR它没有用addEventListener去监听事件,而是用了Dom level 0的方式直接用on事件名添加回调,不然我们就需要去劫持addEventListener了,那可是个大麻烦,一不小心就会捅大篓子的。
对象属性的劫持当然是用defineProperty大法,把onreadystatechange回调改写,如果mock匹配到了url,就用假数据返回,如果没匹配到当然不能影响其它正常的ajax接口了,触发原始xhr的流程。下面是完整的可运行的代码,为了方便演示,我把几个不常用的属性和正则匹配url规则库的地方省略了用固定地址。
var __XMLHttpRequest=XMLHttpRequest; window.XMLHttpRequest=function (){ var resultObj={ xhr:new __XMLHttpRequest(), onreadystatechange:null, open:function (method,url,async){ this.url=url; this.method=method; }, send:function (data){ //用异步改下时序,让send 在 onreadystatechange 之后再执行 setTimeout(()=> { if(this.url.indexOf("http://www.baidu.com/post")>=0){ //匹配url规则,这个是业务代码省略掉了,先用固定地址 this.readyState=4; this.status=200; this.responseText="{result:'hello,baidu'}"; //为了演示先写死报文了 this.onreadystatechange({mock:true}); }else{ this.xhr.open(this.method,this.url); this.xhr.send(data); } }, 0); } } Object.defineProperty(resultObj,"onreadystatechange", { get:function (){ return this.xhr.onreadystatechange; }, set:function (func){ this.xhr.onreadystatechange= (arg)=>{ if(arg.mock){ //mock接口,直接触发回调 func(); }else{ //没匹配到,把原始xhr得到的数据复制回来 this.readyState=this.xhr.readyState; this.status=this.xhr.status; this.responseText=this.xhr.responseText; func(); } }; } }) return resultObj; } 复制代码
我们写个用例跑一下,注:为了简化代码,上面匹配url的地方写死了,只能用http://www.baidu.com/post这个地址
var xhr=new XMLHttpRequest() xhr.open("post","http://www.baidu.com/post"); xhr.send(); xhr.onreadystatechange=function (){ console.log(xhr.responseText) } 复制代码
完美运行,输出了 {result:'hello,baidu'} ,这在以前是不敢想象的,ajax请求一个不存在的地址也能返回报文 。。。
真正的黑科技2:无侵入式接口层异常监控,把问题优雅的甩锅给后台的方法
多年以前,用户经常出现一些问题,开发难以重现,后台同学神经比较大,不怕不怕啦,经常不记日志,或是称查不到日志,前端又没日志,最后基本都是前端背责任,后来我们前端团队就实现了在xhr 层包装了一层监控后台接口的异常和超时现象,优雅的甩锅给后台,节省好多时间(其实很多是服务器问题或是网络原因,后台真的查不出来)。多年之后,我实现了mock 之后,才想到其实直接劫持xhr才是更好的方案,可以通用于一切项目,去年看到有公司做出来了:www.fundebug.com,感到很欣慰,很多想法和我不谋而合。其实这样一个解决方案要产品化还是很难的,一项技术到产品化之间有巨大的鸿沟。
来讲讲它的核心原理吧
-
首先脚本异常的全局捕获,有window.onerror全局事件,在node.js端,有uncaughtException事件,可以捕获到异常的类型,错误堆栈信息,技术真的是日新月异了,想当年IE浏览器时代,onerror事件根本没啥参数,想获得异常堆栈只能通过arguments.callee.caller一级级往上回溯堆栈函数再toString。
-
然后是接口层异常捕获,有了上面的mock.js代码之后,要实现无侵入式的接口异常检测很容易了,mock如果没匹配到会正常发ajax请求的,直接在 readystatechange里检测状态码和报文,如果发现状态码异常就上报,当然,如果你的后台报错仍然返回200状态码的话,那就只能制定报文规范,约定成功的返回值,如果检测不到成功的关键字,一律按失败处理,上报日志。
-
接口的超时检测可以在send时加一个setTimeout计时,如果指定的时候还没有触发onreadystatechange,就上报超时日志。
其实就是在上面mock.js的基础上,加几行代码就行实现,不详细贴代码了,大致代码如下:
this.xhr.onreadystatechange= (arg)=>{ if(arg.mock){ //mock接口,直接触发回调 func(); }else{ //没匹配到,把原始xhr得到的数据复制回来 if(this.readyState==4 && this.status!=200){ reportError() //上报日志 } //.......省略 } }; 复制代码
以上所述就是小编给大家介绍的《函数劫持能做啥?前端黑科技揭秘》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
JSP网站开发四“酷”全书
万峰科技 / 电子工业出版社 / 2005-9 / 49.00元
本书以JSP为开发语言,选取当前最流行、最具代表性的4类网站:新闻站点、论坛、电子商城和博客(Blog)系统为例,详细介绍了使用JSP开发网站的核心技术。掌握了本书所举4类网站的开发技术,将帮助你成为网站开发的“全能冠军”。 本书结合作者多年在网站系统开发方面的经验,从系统的需求分析开始,确定系统的流程与设计,到模块的划分,再到数据加结构的设计,最后开始每个模块编程开发,贯穿了网站开......一起来看看 《JSP网站开发四“酷”全书》 这本书的介绍吧!