Cxxjackie点评
@grant unsafeWindow并不是一句很方便的声明,他潜在造成的问题可能比你想象的多,在这一模式下很多原生的函数、对象会被油猴接管,比如setTimeout/clearTimeout、setInterval/clearInterval,在某些情况下可能造成意料之外的错误,解决方法通常是在前面加一个“unsafeWindow.”以确保得到的是原生引用。关于这个document的问题,在unsafeWindow + document-start的前提下,如果你想避免麻烦,最好在代码前加上这句:
const document = unsafeWindow.document;
大总结
我们在脚本的初始化的过程中
对window进行了代理,叫做context
而context存在一个get函数
我们油猴脚本的函数的this就是这个代理过得window
而unsafewindow而是没有经过代理的window
代理的window会做各式各样的操作
例如如我们在函数内访问document
实际是访问的代理window的document
参考https://bbs.tampermonkey.net.cn/thread-2494-1-1.html
此时会触发代理window的get函数
get函数发现是document会执行对象的处理函数
此时会执行ee函数
ee函数则会在其内部执行N、M、I三个函数
N函数则对evalute进行了修改
参考https://bbs.tampermonkey.net.cn/thread-2495-1-1.html
M函数对["write", "writeln", "open", "close"]进行了修改
参考https://bbs.tampermonkey.net.cn/thread-2496-1-1.html
I函数对addEventListener和removeEventListener进行了修改
参考https://bbs.tampermonkey.net.cn/thread-2497-1-1.html
也就是说在我们油猴脚本内访问各式各样window的函数
都会触发相应的get并且有各种行为来为其进行保驾护航
而我们之所以在脚本内访问dcoument函数后使用
EventTarget.prototype.addEventListener劫持失败
是因为我们在函数内部使用了document
触发了油猴的get,然后对其addEventListener进行劫持了
而默认的addEventListener在其原型链上
document自身没有addEventListener函数
如果油猴对其document自身设置了addEventListener
则根据原型链原则不会调用原型上的addEventListener函数
所以我们EventTarget.prototype.addEventListener无效
其他属性也是同理
结语
撒花~