关闭`@grant none`会破坏我的Greasemonkey脚本?

我在Facebook主页上运行此脚本。 它会在底部的Dock中获取所有对话并获取它们的__FB_TOKEN

 // ==UserScript== // @name MyScript // @namespace MyNameSpance // @include /https?://(www.)?facebook.com(/.*)?/ // @require http://code.jquery.com/jquery-2.1.0.min.js // @version 0.0.0 // @grant none // ==/UserScript== (function () { // Don't run on frames or iframes if (window.top != window.self) { return ; } window.addEventListener('load', function () { var element = $('.fbNubGroup.clearfix.videoCallEnabled'); console.log('SCRIPT ELEMENT: ', element); // is displayed on the console var children = element.children(); console.log('SCRIPT CHILDREN: ', children); // is displayed on the console for (var i = 0; i < children.length; i++) { var child = $(children[i]); console.log('SCRIPT CHILD: ', child); // is displayed on the console /* child : Object [div.someClasses] + 0: div.someClasses + __FB_TOKEN: [ 267 ] */ console.log('SCRIPT CHILD[0]: ', child[0]); // is displayed on the console console.log('SCRIPT CHILD[0].__FB_TOKEN:', child[0].__FB_TOKEN); // UNDEFINED var key = child[0].__FB_TOKEN[0]; console.log('SCRIPT KEY: ', key); // not displayed } }, false); }) (); 

使用@grant none ,它按预期工作,我得到:

grant_none

但是,如果我将@grant none更改为@grant GM_xmlhttpRequest ,则该脚本将不再起作用。 它给:

grant GM_xmlhttpRequest

并在child[0].__FB_TOKEN行上引发exception。

我不明白为什么,因为CHILD[0]没有改变:

child

为什么更改@grant none破坏脚本?

当你从@grant none切换到@grant GM_xmlhttpRequest , Greasemonkey会重新打开沙盒, 作为副作用
(坦率地说,所有GM开发人员和脚本都应该始终使用沙箱运行 – 极少数例外。这避免了“定时炸弹”编码问题和头脑风暴这样的问题。)

JavaScript对象,数组,变量和函数无法跨越沙箱。 但是,作为有限的解决方法,将unsafeWindow提供给Greasemonkey范围。

这个问题也很重要:

  1. Greasemonkey(和Firefox)只是使用unsafeWindow关闭了一些以前可能的解决方案 。
  2. jQuery是一个特殊情况,并且非常难以将非DOM对象用于沙箱。

解:

  1. 由于__FB_TOKEN是一个数组,因此必须使用unsafeWindow将其传递到沙箱中。
  2. 在这种情况下尝试使用jQuery会产生令人无法接受的高头痛与结果比率; 所以使用普通的DOM方法。

将所有内容放在一起脚本变为:

 // ==UserScript== // @name _MyScript // @namespace MyNameSpace // @include /https?://(www.)?facebook.com(/.*)?/ // @require http://code.jquery.com/jquery-2.1.0.min.js // @version 0.0.0 // @grant GM_xmlhttpRequest // ==/UserScript== (function () { // Don't run on frames or iframes if (window.top != window.self) { return; } window.addEventListener ('load', function () { /*--- This unsafeWindow is key. After that, don't use any jQuery while trying to get at javascript objects like __FB_TOKEN. */ var element = unsafeWindow.document.querySelector ( '.fbNubGroup.clearfix.videoCallEnabled' ); /*-- Used console.info to make it easier to spot messages buried in all the Facebook console crud. */ console.info ('SCRIPT ELEMENT: ', element); var children = element.children; console.info ('SCRIPT CHILDREN: ', children); for (var i = 0; i < children.length; i++) { var child = children[i]; console.info ('SCRIPT CHILD: ', child); /* child : Object [div.someClasses] + 0: div.someClasses + __FB_TOKEN: [ 267 ] */ console.info ('SCRIPT CHILD: ', child); console.info ('SCRIPT CHILD.__FB_TOKEN:', child.__FB_TOKEN); var key = child.__FB_TOKEN[0]; console.info ('SCRIPT KEY: ', key); } }, false); } ) ();