3

2011 年の Google I/O プレゼンテーションを見ています https://www.youtube.com/watch?v=M3uWx-fhjUc

39:31 の時点で、Michael はクロージャ コンパイラの出力を示しています。これは、以下に含まれるコードのようなものです。

私の質問は、このコードが正確に何をしているのかです (どのように、なぜ)

// Question #1 - floor & random? 2147483648?
Math.floor(Math.random() * 2147483648).toString(36);

var b = /&/g, 
    c = /</g,d=/>/g, 
    e = /\"/g, 
    f = /[&<>\"]/;

// Question #2 - sanitizing input, I get it... 
// but f.test(a) && ([replaces]) ?
function g(a) {
   a = String(a);

   f.test(a) && (
      a.indexOf("&") != -1 && (a = a.replace(b, "&amp;")), 
      a.indexOf("<") != -1 && (a = a.replace(c, "&lt;")), 
      a.indexOf(">") != -1 && (a = a.replace(d, "&gt;")),
      a.indexOf('"') != -1 && (a = a.replace(e, "&quot;"))
   );

   return a;
};

// Question #3 - void 0 ???    
var h = document.getElementById("submit-button"),
    i,
    j = {
       label: void 0,
       a: void 0
    };
i = '<button title="' + g(j.a) + '"><span>' + g(j.label) + "</span></button>";
h.innerHTML = i;

編集

洞察に満ちた回答をありがとう。コンパイラがスクリプトの先頭でランダムな文字列生成をスローした理由について、私はまだ本当に興味があります。きっとそれにはちゃんとした理由があるはずです。誰???

4

4 に答える 4

2

1) 1 番のポイントが何かわかりません。

2) シンボルが対応するHTML エンティティに適切に変換されていることを確認するため、基本的に入力をサニタイズして、HTML が安全であることを確認します。

3)void 0は、本質的にそれが確実に返されることを確認するための本当に安全な方法undefinedです。JavaScriptの実際のキーワードは変更可能 (つまり、別のものに設定できる) であるため、期待する未定義の値と実際に等しいとundefined仮定するのは必ずしも安全ではありません。undefined

于 2013-08-21T22:31:25.880 に答える
2

疑わしい場合は、他のベースを確認してください。

2147483648 (基数 10) = 0x80000000 (基数 16)。したがって、32 ビットの signed の範囲内にある乱数を作成しているだけintです。floorそれを実際の int にtoString(36)変換してから、36 文字のアルファベットに変換します。これは 0-9 (10 文字) と az (26 文字) です。

その最初の行の最終結果は、乱数と文字の文字列です。それらは 6 つ (36^6 = 2176782336) ありますが、最初のものは他のものほどランダムではありません (アルファベットの遅れはありません)。編集:エイドリアンは彼の答えでこれを適切に解決しました。最初の文字は 36 文字のいずれでもかまいませんが、Z である可能性はわずかに低くなります。他の文字は、低い値に少し偏っています。

質問 2 については、これを意味する場合はa = String(a);、はい、それがa文字列であることを確認しています。これはコンパイラへのヒントでもあり、マシンコードに変換できる場合は最適化を改善できます (ただし、文字列を変換できるかどうかはわかりません)。

編集:質問を明確にしました。f.test(a) && (...)短絡評価を使用する一般的なトリックです。効果的に言っていif(f.test(a)){...}ます。実際のコードではそのように使用しないでください。読みにくくなるからです (場合によっては読みやすくなります)。について疑問に思っている場合testは、正規表現に関係しています。

質問 3 は、私にとっても初めてのことです。しかし、ここを参照してください: `void 0` とはどういう意味ですか? (グーグルで検索してみてください。興味深いのですが、奇妙であることがわかりました)

于 2013-08-21T22:29:20.573 に答える
2

1) このコードは Closure Library から取得されます。このコードは、ランダムな文字列を作成するだけです。それ以降のバージョンでは、文字列に連結される大きなランダムな整数を単純に作成するために置き換えられました。

'closure_uid_'  + ((Math.random() * 1e9) >>> 0)

この簡略化されたバージョンは、Closure Compiler が削除しやすいため、以前のように残っていることはありません。具体的には、コンパイラは、引数のない "toString" が目に見える状態の変化を引き起こさないと想定します。ただし、パラメーターを使用した toString 呼び出しについては、同じ想定はしていません。コンパイラの仮定について詳しくは、次を参照してください。

https://code.google.com/p/closure-compiler/wiki/CompilerAssumptions

2) ある時点で、ほとんどの文字列をエスケープする必要がないという前提で、「置換」呼び出しを行う前に、置換する必要がある可能性のある文字をテストする方が速いと誰かが判断しました。

3) 他の人が述べているように、void 演算子は常に未定義を返します。「void 0」は単に「未定義」を記述するための合理的な方法です。通常の使用ではかなり使い物になりません。

于 2013-08-22T21:59:14.963 に答える
2

さまざまな質問が 1 つにまとめられていますが、質問のタイトルを考慮して、ここでは最初の質問に焦点を当てます。

Math.floor(Math.random() * 2147483648).toString(36);

実際には、これは何もしません- 値が代入されるのではなく破棄されるからです。ただし、これの考え方は、0 から 2 ^ 31 - 1 の間の数値を生成し、基数 36 で返すことです。

Math.random() は、0 (含む) から 1 (含まない) までの数値を返します。次に、2^31 を掛けて、前述の範囲を生成します。次に.toString(36)、0 から 9 の後に A から Z が続く 36 進数に変換します。

最終結果の範囲は 0 から (私が信じている) ZIK0ZI までです。

そもそもなぜそこにあるのか...まあ、スライドを調べてください。この行は一番上に表示されます。これは純粋な推測ですが、実際には、コードが見える範囲まで切り詰められており、そのすぐ上にこれが割り当てられた何かがあったのではないかと疑っています。

于 2013-08-21T22:29:34.917 に答える