6

ローカルvarステートメントが引数に置き換えられるような関数を作成すると、パフォーマンスが低下しますか? 例:

function howManyMatch(arr, pattern, /*ignored:*/ i, l, total) {
  l = arr.length;
  total = 0;
  for (i = 0, i < l; i++) {
    if (pattern.test(arr[i]))
      total++;
  return total;
}

いくつかの利点:

  • 小さい縮小サイズ:varステートメントなし。
  • varできるだけ少ない s を使おうとするプログラマーの時間が減る
  • 1 か所で定義されたすべてのローカル変数

...そして欠点:

  • arguments思いがけない方法で変更される可能性があります。下記参照
  • vars がローカルであるという本体の明確性が低い
  • 何もしない引数を見ると混乱する
  • 誰かが無意識のうちにそれらを削除した場合、コードはグローバルに書き込みます

それでも、ミニファイヤがより多くのビットを自動的に絞り出す簡単な方法かもしれません。

更新:これまでに言及されていない大きな欠点: 関数が N 個のパラメーターで呼び出された場合、最初の N 個の項目がarguments引数リストの最初の N 個の識別子にバインドされます ( 10.1.8 の最後の箇条書きを参照)。このことを考慮:

function processStuff(/*ignored:*/i, j, k) {
    // use i/j/k to loop
    // do stuff with the arguments pseudo-array
}

上記の例では、 を呼び出した場合、 and をprocessStuff(stuff1, stuff2)設定すると、 iandjがそれぞれ上書きarguments[0]されarguments[1]ます。

4

5 に答える 5

5

いいえ、これをしないでください。それは紛らわしく、不必要です。そして、私はあなたの「利点」のリストが非常に疑わしいと思います-そこにあるすべての項目は、実際に得られる利益に関して非常に薄いです。

必要な場合は、コンマ演算子を使用して、関数の先頭にある1つのステートメントですべての変数を宣言します(とにかく、これらはこの場所に引き上げられます。

function howManyMatch(arr, pattern) {
  var i, l, total;
  // rest
}

または、すべてを1つのステップで宣言/定義することもできます

function howManyMatch(arr, pattern) {
  var l = arr.length, total = 0, i = 0;
  // rest
}
于 2010-12-06T21:15:00.373 に答える
4

私はあなたがすでに知っている多くの理由でそれをしません、個人的に私は引数と変数の意味論的意味を混合するという事実が好きではありませんが、実装レベルでは、関数が実行されるとき、それらは単なるプロパティです現在の変数オブジェクトの中で、それらは異なる意味のIMOを持っています。

さて、質問に答えると、パフォーマンスへの影響はないと思います

変数のインスタンス化プロセスについて少しお話ししましょう。これは、関数が実行される直前(一般に「巻き上げ」と呼ばれます)の関数コードに対して実行されます。最初は、関数について説明されているすべての正式なパラメーターが現在のパラメーターにバインドされます。変数オブジェクト(現在のスコープ)。これらは、関数呼び出しで渡された値で初期化undefinedされます。指定されていない場合は初期化されます。

その後var、関数内のすべてのステートメントに属するすべての識別子が現在のスコープで宣言され、で初期化されますundefined(この後に割り当てが行われることに注意してください。関数本体は、実際にはまだ実行されていません)。

3番目のステップはFunctionDeclarationsです。関数宣言のすべての識別子はローカルスコープにバインドされます。識別子が以前に宣言されている場合、その値は次のように置き換えられます。

(function (a) {
  return typeof a; // "function", not "string"

  function a () {}

})('foo');  // <-- passing a string

代わりに、関数の上部にある単一のvarステートメントを使用することをお勧めします。

function howManyMatch(arr, pattern) {
  var l = arr.length,
      total = 0, i;
  for (i = 0, i < l; i++) {
    if pattern.test(arr[i]) && total++;
  return total;
}

これはコードを整理するだけでなく、JavaScriptの関数のみのスコープと、の「巻き上げ」の性質による望ましくない結果を防ぐのに役立ちます。JSLintvarなどの一部のツールもこれを推奨しています。

于 2010-12-06T21:15:16.567 に答える
1

ここでは、読みやすさと保守性がファイルサイズとマイクロ最適化よりも重要だと思います。キーワードを持つコードを読む方がはるかに簡単です。varそれに加えて、スコープごとに1つのvarステートメントで十分です(とにかく、JavaScriptがそれらを持ち上げる場所です)。すべてのローカル変数は、ローカルスコープ内のどこでも使用できます(宣言された順序に関係なく)。したがって、読みやすくするために、すべてのローカル変数を同じ位置(ローカルスコープの先頭)で宣言する必要があります。ステートメントのこれらの4バイトは、ユーザーがローカル変数の初期値varを設定できるようにすることで、考えられるバグを導入する価値がありません。追加のパラメーターを使用してその関数を呼び出すことによって。カプセル化が壊れます(これは正しく行うことができますが、省略して保存したバイト数よりも多くのバイト数になりますvar)。それに加えて、あなたのコードを読もうとしている人にとっては本当に混乱します。

于 2010-12-06T21:15:19.497 に答える
0

"Test-Driven Javascript Development"(2011) の Chistian Johansen は次のように述べています。オブジェクトはいくらかのオーバーヘッドを誘発し、ブラウザーがそれを使用しない機能を最適化することを示します。」

于 2012-06-14T14:22:44.513 に答える
0

varキーワードを削除するだけで、同じ利点が得られます。

function howManyMatch(arr, pattern) {
  l = arr.length;
  total = 0;
  for (i = 0; i < l; i++) {
    if pattern.test(arr[i]) && total++;
  return total;
}

この場合、すべての変数を値 ( , , )varで定義しているため、キーワードを明示的に記述する必要はありません。l = arr.lengthtotal = 0i = 0

ところで、変数を関数の引数として定義して変数を事前定義することはできないことに注意してください。これは不可能です。例えば:

function howManyMatch(arr, pattern, i=0, l, total = 0){ ... }

したがって、欠点が残っているため、コードを縮小するソリューションは結局のところ非常に役立つとは思いません;)


編集

varキーワードなしで変数を定義すると、それらがグローバルになるという事実については考えていませんでした。それはあなたがまったく望んでいないことかもしれません...

しかし、この問題についてもう一度考えてみると、関数の引数で変数を定義する理由がわかりません。その方法に与えるすべての利点は、基本的にこの例にも当てはまります。

function howManyMatch(arr, pattern) {
  var l = arr.length, total = 0, i=0;
  for (; i < l; i++) {
    if pattern.test(arr[i]) && total++;
  return total;
}

そして、この例はさらに短いです。

于 2010-12-06T21:00:40.887 に答える