4

Javascript (ECMAscript) は、Array.prototype.forEachバージョン 1.6 (ECMAscript エディション 3、2005) 以降のメソッドをサポートしています。そのため、かなり多くのブラウザがすでにそのメソッドをサポートしており$.each()、たとえば jQuery のメソッドと比較して信じられないほど高速です。
(実際には、どの Javascript ライブラリーに関係なく、すべての実装に勝っています)

jQuery と比較すると、約 60 ~ 70% 高速です。JSPerfのforEach と jQueryで試してみてください。

これまで使用してきた唯一の欠点は、イテレーションを早期に中断する方法がわからないことです。for, whileand do-whilehave aステートメントと同様にbreak、jQuerysはループを中断する.each()をサポートしてreturn falseいます。

ECMAScript Edition 5 の仕様(私が見つけた最新のもの)を調べましたが、そのループからの早期のブレークについては言及されていません。

では、質問ですが、ダグラス・クロックフォード氏はこれを と呼びdesign errorますか?
私は何かを見逃していますか?そのようなループを早期に中断することは可能ですか?

編集

これまでの回答に感謝します。誰も「ネイティブ」ソリューションを思い付いていないので、そのための実装は実際にはありません(おそらく機能ですか?)。とにかく、私は提案された方法があまり好きではないので、少しだまされて、最終的に私が好きな方法を見つけました(少なくとも、より良い)。次のように見えます:

var div     = document.createElement('div'),
divStyle    = div.style,
support     = jQuery.support,
arr         = ['MozTransform', 'WebkitTransform', 'OTransform'];

arr.slice(0).forEach(function(v,i,a){    
    if(divStyle[v] === ''){
       support.transform = v;
       a.length = 0;
    }
});

これは「実際の」製品コードです。私は css3 変換プロパティを検索する良い方法を探していましたが、ecma5 仕様と奇妙な Javascript フォーラムで迷子になりました :-)

したがって、配列オブジェクト自体を 3 番目のパラメーターとして.forEachコールバックに渡すことができます。探しているものが見つかったらすぐに、元の配列からコピーを作成し、slice(0)そのプロパティを呼び出して 0 に設定します。.length非常にうまく機能します。

誰かがより良い解決策を思いついたら、もちろんこれを編集します。

4

4 に答える 4

7

代わりに使用できますevery。この関数はtrue、提供されたコールバック関数がtrue配列内のすべての要素に対して (true) を返した場合に戻り、そうでない場合に戻るように設計されてfalseいます。ここでの重要なポイントは、コールバック関数が偽の値を返すと、配列の残りの部分を反復せずにeveryすぐに戻ることです。falseしたがって、戻り値を無視して、 であるかのeveryように扱いforEachます。

[1, 2, 3, 4, 5].every(function(e) {
   alert(e);

   if (e > 2) return false; //break

   return true;
});

この例でalertは、3 回しか発火しません。

もちろん、ここでの大きな注意点は、ループを続行したい場合は、真の値を返さなければならないということです。実際、何も返さない (未定義) 場合、ループは停止します。someまたは、まったく逆の動作をする which を使用することもできます。コールバック関数が真の値を返す場合はすぐに true を返し、そうでない場合は false を返します。この場合、return true「break」ステートメントになります。逆方向は可能ですreturn trueが、単純にループを継続する必要がなくなります。

ここで、パフォーマンスに関心がある場合は、通常のforループのみを使用することをお勧めします。これは、関数を呼び出すときにかなりのオーバーヘッドが発生し、配列が大きくなるとすぐに加算されるためです。ネイティブ関数を使用すると多少は効果がありますが、ユーザー定義関数を繰り返し呼び出すことによるオーバーヘッドは依然として存在し、些細なことではありません。少なくともこれは私の経験です。もちろん、独自のテストを行う必要があります。

于 2010-10-19T22:08:21.113 に答える
1

I would assume that you have a chunk of code that needs to be run against every single element. Don't use forEach to find an element or likewise "stop in the middle" operations. Apply this function to every element in an array.

You could (I think) use some sort of global indicator to check and return false if "found" or something.

var found = false;
array.forEach(function (k, v) { 
    if (found) 
    { 
        return false; 
    } 
    else 
    { 
        if (v == 1) 
        { 
            found = true; 
        }
    } 
}); 
于 2010-10-19T19:57:26.083 に答える
1

エラーをスローして、反復から抜け出すことができます。

if (typeof BreakIteration == "undefined") {
  BreakIteration = new Error("BreakIteration");
}

try {
    [0,1,2,3,4].forEach(function(key, value) {            
        console.log(key + ': ' + value);

        if (value == 3) {
            throw BreakIteration;
        }
    });
} catch (error) {
    if (error !== BreakIteration) {
        throw error;
    }
}

これはまったくきれいではありません。同意します -- 仕様のバグです。

于 2010-10-19T20:11:12.913 に答える
0

ループして検索したい場合は、他の構造を使用すると思います。

forEach-ing から抜け出すためのオプションはもちろんthrow何かですが、実際には throw を使用したい方法ではありません...

于 2010-10-19T20:10:46.443 に答える