0

在 Firefox 和 Chrome 的控制台中,这有效(警报脚本内容):

var script = document.createElement("script");
script.textContent = (
    function test() {
        var a = 1;
    }
);
document.getElementsByTagName("head")[0].appendChild(script);
alert(document.getElementsByTagName("head")[0].lastChild.textContent);

将此代码用作 Firefox 的 Greasemonkey 脚本也可以。

现在,如果想在 Firefox/Chrome 控制台和 Greasemonkey 脚本中添加“私有方法” do()test()它不再起作用:

var script = document.createElement("script");
script.textContent = (
    function test() {
        var a = 1;
        var do = function () {
            var b = 2;
        };
    }
);
document.getElementsByTagName("head")[0].appendChild(script);
alert(document.getElementsByTagName("head")[0].lastChild.textContent);

为了在 Greasemonkey 脚本中完成这项工作,我必须将所有代码放在一个CDATA 标签块中:

var script = document.createElement("script");
script.textContent = (<![CDATA[
    function test() {
        var a = 1;
        var do = function() {
            var b = 2;
        };
    }
]]>);
document.getElementsByTagName("head")[0].appendChild(script);
alert(document.getElementsByTagName("head")[0].lastChild.textContent);

这仅适用于 Greasemonkey 脚本;它从 Firefox/Chrome 控制台引发错误。我不明白为什么我应该使用CDATA标签,因为我没有使用 XHTML,所以这里没有要遵守的 XML 规则。

为了使它在 Firefox 控制台(或 Firebug)中工作,我需要CDATA放入标签,如<>and </>

var script = document.createElement("script");
script.textContent = (<><![CDATA[
    function test() {
        var a = 1;
        var do = function() {
            var b = 2;
        };
    }
]]></>);
document.getElementsByTagName("head")[0].appendChild(script);
alert(document.getElementsByTagName("head")[0].lastChild.textContent);

这在 Chrome 控制台中不起作用。我试过.toString()像很多人一样在末尾添加(]]></>).toString();),但它没用。

我试图用标签名称替换<>和,但这也不起作用。</><foo> </foo>

var do = function(){}如果我在另一个函数中定义,为什么我的第一个代码片段不起作用?

CDATA即使我不使用 XHTML,为什么还要使用它作为解决方法?

如果它在没有 Greasemonkey 脚本的情况下工作,我为什么要<> </>为 Firefox 控制台添加?

最后,Chrome和其他浏览器的解决方案是什么?

编辑:

我的错,我从来没有在 JS 中使用过 do-while 并且我在一个简单的文本编辑器中创建了这个示例,所以我没有看到“do”是保留关键字:p

但是问题仍然存在,我没有在我的示例中初始化 Javascript 类。有了这个新示例,CDATAGreasemonkey 需要CDATA,E4X<> </>和 Chrome 之间的 Firefox 需要失败:

var script = document.createElement("script");
script.textContent = (
<><![CDATA[var aClass = new AClass();
function AClass() {
    var a = 1;
    var aPrivateMethod = function() {
        var b = 2;
        alert(b);
    };
    this.aPublicMethod = function() {
        var c = 3;
        alert(c);
    };
}
aClass.aPublicMethod();]]></>
);
document.getElementsByTagName("head")[0].appendChild(script);

问:为什么?

4

2 回答 2

4

这里有多个错误/问题:

  1. 添加私有方法do()不起作用,因为do是保留字
    此代码在 FF 和 Chrome(以及 GM 脚本)中都可以正常工作:

    var functionVar = (
        function test() {
            var a = 1;
            var properlyNamedVariable = function() {
                var b = 2;
            };
        }
    );
    console.log (functionVar.toString() );
    

    如果你使用描述性的变量名,你不仅会在将来为自己省去很多麻烦,而且你几乎不会不小心使用保留字。

  2. 回复:"To make this work in a Greasemonkey script, I have to put all code in a CDATA tag"

    不,该代码不起作用 发生的事情是错误发生在evalGreasemonkey 沙箱中的 'd 范围内,并且没有报告给 Firefox 的错误控制台。也就是说,它默默地失败了。
    如果您尝试test();从控制台执行,则会收到错误消息:ReferenceError: test is not defined. 然而,如果您删除var do = function ...代码并重新加载页面,那么您可以test()从控制台调用。

  3. 同样,script.textContent = (<><![CDATA[ ...代码也不起作用。它也默默地失败并且test()没有被定义。这是一种与前面的示例略有不同的静默故障。

  4. 依赖该(<><![CDATA[ ...技巧的代码在 Chrome 中不起作用,因为 Chrome 不支持在 javascript 中对 XML 进行内联处理。这是支持 E4X的 Firefox 的一项额外功能,而 Chrome 不支持。

  5. 格式化您的代码,这样阅读起来就不会那么麻烦了。


所以,总结一下:

  1. 对变量、函数等使用描述性名称。
  2. 请注意您使用的语言中的保留字。
  3. 谨防无声的失败。不幸的是,这些发生在各种 Greasemonkey 场景中。
  4. 不同的浏览器支持不同的功能。

这是一种适用于 Firefox、Chrome、其他几种浏览器以及 Greasemonkey、Tampermonkey、Scriptish 等的技术。它还有助于调试和测试,因为代码与内联变量声明是分开的:

  1. 定义您的函数或正常代码:

    function testMyAdhocCode () {
        "use strict";    
        var importInteger   = 1;
        var imA_PrivateFunction = function () {
            var someOtherInteger = 2;
    
            console.log (
                "importInteger = ", importInteger,
                "  ||  someOtherInteger = ", someOtherInteger
            );
        };
    
        console.log ("Greetings from testMyAdhocCode()!");
        imA_PrivateFunction ();
    }
    


  2. 然后像这样将它注入到页面中(如果必须的话。最好不要注入代码,如果你能提供帮助的话。):

    addJS_Node (testMyAdhocCode);   //-- Function is just created.
    
    // OR
    addJS_Node (null, null, testMyAdhocCode); //-- Function is created and immediately run.
    
    // OR
    addJS_Node ("var someVar = 86;") //-- Adhoc code
    
    // OR
    addJS_Node ("preExistingFunction (42); ") //-- Run a preexisting function.
    


  3. addJS_Node()您的脚本中包含的位置为:

    function addJS_Node (text, s_URL, funcToRun, runOnLoad) {
        var D                                   = document;
        var scriptNode                          = D.createElement ('script');
        if (runOnLoad) {
            //--- Doesn't always fire on Chrome. Needs @run-at document-start.
            scriptNode.addEventListener ("load", runOnLoad, false);
        }
        scriptNode.type                         = "text/javascript";
        if (text)       scriptNode.textContent  = text;
        if (s_URL)      scriptNode.src          = s_URL;
        if (funcToRun)  scriptNode.textContent  = '(' + funcToRun.toString() + ')()';
    
        var targ = D.getElementsByTagName ('head')[0] || D.body || D.documentElement;
        targ.appendChild (scriptNode);
    }
    




更新附加问题:

新问题更是如此。

  • 这是不正确的代码,因此它会在 Firefox 控制台中引发错误。
  • 它使用 E4X 功能,因此无法在 Chrome 中运行。
  • 应该在 Greasemonkey 中引发与在 Firefox 中相同的错误(它们名义上是相同的 JS 引擎),但由于 GM 沙箱脚本的方式纯属愚蠢,您可以摆脱该错误代码(目前)。
  • 不要这样编码!使用类似的函数addJS_Node()

如果你真的必须注入代码,正确的方法是这样的:

function main () {
    "use strict";   // Keep this line!
    var aClass = new aClass();

    function aClass() {
        var a = 1;
        var aPrivateMethod = function() {
            var b = 2;
            alert(b);
        };
        this.aPublicMethod = function() {
            var c = 3;
            alert(c);
        };
    }

    aClass.aPublicMethod();

    //-- PUT ALL OF THE REST OF YOUR INJECTED CODE HERE.
}

addJS_Node (null, null, main);

将所有内容都放在目标页面的全局范围内是个坏主意!但是,如果你坚持这样做,代码是这样的:

function aClass() {
    "use strict";   // Keep this line!
    var a = 1;
    var aPrivateMethod = function() {
        var b = 2;
        alert(b);
    };
    this.aPublicMethod = function() {
        var c = 3;
        alert(c);
    };
}

addJS_Node (aClass);
addJS_Node (
      'var aClass = new aClass();'
    + 'aClass.aPublicMethod();'
);
于 2012-06-23T05:37:53.743 回答
1

@BrockAdams 的所有权利为什么需要 CDATA 而不是在所有地方都以相同的方式工作?对于将所有内容写入函数并将内容插入脚本标签的想法,谢谢。

感谢@polygenelubricants javascript get function body仅用于获取 main() 函数内容,而不是包含其内容的函数。

var script = document.createElement("script");
function main()
{
var aClass = new AClass();
function AClass()
{
    var a = 1;
    var aPrivateMethod = function() {
        var b = 2;
        alert(b);
    };
    this.aPublicMethod = function() {
        var c = 3;
        alert(c);
    };
}
aClass.aPublicMethod();
}
var entire = main.toString();
var body = entire.substring(entire.indexOf("{") + 2, entire.lastIndexOf("}"));
script.textContent = body;
document.getElementsByTagName("head")[0].appendChild(script);

entire.indexOf("{")不选择“{”字符并且在脚本标记内容的开头没有空白新行需要“+2” 。

Javascript类函数不应该和我们保存类实例的变量同名,在FirefoxaClass.aPublicMethod();中只会在你第一次执行代码时自动调用(你不能覆盖类函数),Chrome不关心符号,它的工作原理。

因此,我为类名选择了 AClass,为类对象选择了 aClass。

奇怪的是,当我们使用 .toString() 方法时,Firefox 似乎正在以他喜欢的方式解析/显示函数,例如当插入脚本时,它在 Firefox Inspector 中的内容将仅显示在一行中。即使我们在插入 main() 函数时删除了空格,Firebug 也会在每个新行之前使用“制表符”空格格式化代码(因为 Firebug 知道在子字符串之前有 main() 函数,所以它添加了自动空格)。Firebug 在 AClass() 函数前后也增加了一个新行;当函数返回值保存在变量中时,如 aPrivateMethod 或 aPublicMethod,它显示在 1 行。Firebug 的另一个奇怪变化是var aClass = new AClass();变成var aClass = new AClass;.

function AClass()
{
    // code
}

变成

function AClass() {
    // code
}

等等...

Chrome 控制台始终尊重您在 main() 函数中编写的空格/换行符。

我认为这是调试控制台的创建方式,它并不重要。顺便说一句,我谈到的所有这些修改在使用 E4X 扩展时都不会出现在 Firebug 中。

使用 function.toString() 方法而不是 E4X 扩展时看到差异很有趣。也许有人有解释:)

带有 function.toString() 方法的 Firefox 控制台结果:

var aClass = new AClass; function AClass() { var a = 1; var aPrivateMethod = function () {var b = 2;alert(b);}; this.aPublicMethod = function () {var c = 34;alert(c);}; } aClass.aPublicMethod();

带有 E4X 扩展的 Firefox 控制台结果:

var aClass = new AClass(); function AClass() { var a = 1; var aPrivateMethod = function () { var b = 2; alert(b); }; this.aPublicMethod = function () { var c = 34; alert(c); }; } aClass.aPublicMethod();

带有 function.toString() 方法的 Firebug 结果:

    var aClass = new AClass;

    function AClass() {
        var a = 1;
        var aPrivateMethod = function () {var b = 2;alert(b);};
        this.aPublicMethod = function () {var c = 3;alert(c);};
    }

    aClass.aPublicMethod();

带有 E4X 扩展的 Firebug 结果和带有 function.toString() 方法(不支持 E4X)的 Chrome 控制台结果是相同的:

var aClass = new aClass();
function aClass() {
    var a = 1;
    var aPrivateMethod = function() {
        var b = 2;
        alert(b);
    };
    this.aPublicMethod = function() {
        var c = 3;
        alert(c);
    };
}
aClass.aPublicMethod();

可以相关,E4X 是一种干净的方法,没有子字符串破解,但仅受 Firefox 支持:在 JavaScript 中创建多行字符串

于 2012-06-24T13:00:51.790 回答