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スクリプトとして使用することもできます。

ここで、「プライベートメソッド」を追加したい場合do()test()、Firefox / ChromeコンソールでもGreasemonkeyスクリプトでも、機能しなくなります。

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コンソールからエラーがスローされます。タグを使用する理由がわかりません。XHTMLを使用していないCDATAため、ここで尊重するXMLルールはありません。

Firefoxコンソール(またはFirebug)で機能させるには、次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);

これはChromeコンソールからは機能しません。.toString()多くの人がやっているように()最後に追加してみました]]></>).toString();が、ダメです。

<></>をタグ名に置き換えようとしました<foo> </foo>が、それも機能しませんでした。

var do = function(){}別の関数内で定義すると、最初のコードスニペットが機能しないのはなぜですか?

CDATAXHTMLを使用していないのに、回避策として使用する必要があるのはなぜですか?

<> </>また、Greasemonkeyスクリプトを使用せずに動作している場合、Firefoxコンソールに追加する必要があるのはなぜですか?

最後に、Chromeやその他のブラウザのソリューションは何ですか?

編集:

私の悪いことに、私はdoを使用したことがありません-JSにいる間、この例を単純なテキストエディタで作成したので、「do」が予約キーワードであることがわかりませんでした:p

しかし、問題はまだここにあります。私の例ではJavascriptクラスを初期化していません。この新しい例でCDATAは、Greasemonkeyに必要ですが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()は機能しませんでした! このコードは、FFとChromeの両方(およびGMスクリプト)で正常に機能します。do

    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"

    いいえ、そのコードは機能しませんでした。 何が起こったのかというと、エラーevalはGreasemonkeyのサンドボックスの'dスコープで発生し、Firefoxのエラーコンソールに報告されなかったということです。つまり、黙って失敗しました。
    コンソールから実行しようとするとtest();、次のエラーが発生しますReferenceError: test is not defined。一方、コードを削除しvar do = function ...てページをリロードするとtest()、コンソールから呼び出すことができます。

  3. 同様に、script.textContent = (<><![CDATA[ ...コードも機能しませんでした。また、黙って失敗し、test()定義されませんでした。これは、前の例とは少し異なる種類のサイレント障害です。

  4. Chromeはjavascript内のXMLのインライン処理をサポートしていないため、このトリックに依存するコードは(<><![CDATA[ ...Chromeでは機能しません。これは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では機能しません。
  • Firefoxの場合と同じエラーをGreasemonkeyでスローするはずです(これらは名目上同じ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関数本体は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クラス関数は、クラスインスタンスを保存する変数と同じ名前にするべきではありません。FirefoxではaClass.aPublicMethod();、コードを最初に実行したときにのみ自動的に呼び出されます(クラス関数をオーバーライドすることはできません)。Chromeは気にしません。表記、それは動作します。

そのため、クラス名にはAClassを選択し、クラスオブジェクトにはaClassを選択しました。

不思議なことに、Firefoxは.toString()メソッドを使用すると、関数を好きなように解析/表示しているようです。たとえば、スクリプトが挿入されている場合、FirefoxInspectorのコンテンツは1行でのみ表示されます。Firebugは、main()関数を挿入するときにスペースを削除しても、新しい行ごとに「タブ」スペースを使用してコードをフォーマットします(Firebugは、サブストリングの前にmain()関数があることを知っているため、自動スペースを追加します) )。Firebugは、AClass()関数の前後にも新しい行を追加します。関数の戻り値がaPrivateMethodやaPublicMethodのように変数に保存されると、1行で表示されます。Firebugのもう1つの奇妙な変更は、にvar aClass = new AClass();なることvar aClass = new AClass;です。

function AClass()
{
    // code
}

になります

function AClass() {
    // code
}

等々...

Chromeコンソールは、main()関数で記述したように、常にスペース/新しい行を尊重します。

これがデバッグコンソールの作成方法であり、重要ではないと思います。ちなみに、私が話したこのすべての変更は、E4X拡張機能を使用している場合、Firebugでは表示されません。

E4X拡張機能の代わりにfunction.toString()メソッドを使用すると、違いがわかります。多分誰かが説明を持っています:)

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()メソッドを使用したChromeコンソールの結果(E4Xはサポートされていません)は同じです。

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 に答える