Tampermonkey沙箱环境下为何可识别带window.前缀的变量且无报错?为何指定权限后window.close能成功执行?
嘿,咱们逐个拆解你遇到的这几个沙箱相关问题,结合你的示例脚本来说明:
1. 为什么window.close()能在沙箱里成功执行且不报错?
你的脚本里加了@grant window.close这个关键配置——Tampermonkey的@grant指令相当于给脚本开了权限,把原生浏览器的window.close方法直接注入到了沙箱环境里。所以你调用的window.close()不是沙箱模拟的假方法,而是真实的浏览器原生API。
另外,浏览器对window.close()有个规则:只有由脚本打开的窗口才能被脚本关闭(部分浏览器在特定场景下也允许关闭当前窗口,比如页面本身就是通过脚本启动的)。你说这个操作“仅能临时生效”,大概率是因为后续场景变化后,浏览器的安全策略重新限制了,但脚本执行的瞬间刚好满足关闭条件,所以能成功跑起来且没报错。
2. 为什么unsafeWindow里定义全局变量必须直接操作?
Tampermonkey的沙箱隔离做得很彻底:你脚本里的window是沙箱自己封装的代理对象,和页面真正的全局对象(也就是unsafeWindow指向的那个)完全是两个独立的实体。
- 要是你在沙箱的
window上定义变量,比如window.myVar = 'hello',只会修改沙箱内部的window,页面的全局环境根本看不到这个变量。 - 只有直接操作
unsafeWindow,比如unsafeWindow.myVar = 'hello',才能真正修改页面的全局作用域——因为unsafeWindow就是直接指向页面原生全局对象的,相当于绕过了沙箱的隔离墙。
3. 为什么沙箱里访问window.xxx不会报错?
Tampermonkey给沙箱的window做了个聪明的代理:当你访问window.xxx时,如果沙箱自己的window里没有这个属性,它会自动去unsafeWindow(页面的原生全局对象)里查找对应的属性。
比如你写console.log(window.jQuery),沙箱先查自己有没有jQuery,没有的话就去页面全局环境找,找到了就返回对应的对象,找不到就返回undefined——默认情况下不会抛出“未定义”的错误(除非你开了严格模式,但脚本默认是不开启的)。这就是为啥带window.前缀的变量访问不会报错的原因。
你的示例脚本供参考:
// ==UserScript== // @name temp // @namespace no // @match *:///*:/*/* // @grant unsafeWindow // @grant window.close // ==/UserScript== window.close();
内容的提问来源于stack exchange,提问作者zqdlly

