什么是函数劫持?最近在业务中看到一段逻辑。找了半天也没找到是怎么触发的。后来发现其实是利用了函数劫持,大致如下://原函数varsaveLog=function(log){console.log(`Isavedthelog:${log}`);}//1-保存原函数varoriginSaveLog=saveLog;//2-重写原函数saveLog=function(){constargs=Array.prototype.slice.call(arguments);//3-在重写的函数originSaveLog.apply(null,args)中执行原函数的逻辑;console.log('我想劫持你的函数,用它来做我自己的事情');}saveLog('testSaveLog');大致实现的逻辑就是执行自己的逻辑,比如格式化,通知等,同时每次调用都会保存日志。函数劫持,在函数运行前劫持一个函数,添加我们想要的函数。这个函数真正运行起来的时候,已经不是原来的函数了,而是我们自己添加的函数。这也是我们常见的钩子函数的原理之一。如上例,一般的函数劫持会分为三个步骤:使用一个新的变量保存被劫持的函数,在新的函数中重写被劫持的函数,调用原函数(保存在变量中的函数)新功能。为什么可以这样做?一开始,我对上面的代码还是有疑问的。重新赋值saveLog时,会不会改变originSaveLog的引用点?其实并不会,它只会将saveLog指向另一个引用地址。看下面的例子就很容易理解了:leta={};letb=a;a.name='Gopal';//ture{name:'Gopal'}{name:'Gopal'}console.log(b===a,a,b);基础:当两个对象指向同一个地址时,修改一个对象的属性,另一个对象也会相应改变leta={};letb=a;a={name:'Gopal'};//false{name:'Gopal'}{}console.log(b===a,a,b);基本:当将一个新对象赋值给一个对象变量时,对象变量指向新对象的引用地址,并切断与旧引用的关联。应用场景增强你的函数函数,比如上面第一个例子,在原有函数之上实现特定的逻辑。追踪XSS攻击一般XSS攻击都会先使用alert()等方法输出信息进行测试。这时候,我们可以劫持原来的alert(),向其输入跟踪信息的代码,最后执行原来的函数。如下:functionreport(caller){varimg=newImage();img.src=`https://img.ydisp.cn/news/20220902/qr1bnjp0gyz_alert=window.alert;window.alert=function(s){//获取攻击者的相关信息并上报给report(alert.caller)_alert(s)}alert('test');劫持ajax请求,实现mock功能在mock.js中,是通过原生的XMLHttpRequest(或ActiveXObject)来劫持判断是否找到匹配的数据模板。如果找到,拦截XHR请求逻辑,执行自身规则对应的逻辑。如果未找到匹配的数据模板,则使用本机XHR发送请求。详细代码见这里[1]。总结JavaScript中的函数劫持是一种增强原有功能的技术。通常,我们使用它来增强原始JavaScript全局方法的能力。此处参考[1]:https://github.com/nuysoft/Mock/blob/refactoring/src/mock/xhr/xhr.js
