<something>をN回実行します(宣言構文)


90

JavaScriptにこのようなものを簡単に書く方法はありますか:

[1,2,3].times do {
  something();
}

同様の構文をサポートする可能性のあるライブラリはありますか?

更新:明確にするために- something()各配列要素の反復ごとにそれぞれ1、2、3回呼び出されたい


1
JSにはこのような機能はなく、不足している機能の上位5つです。何よりも、ソフトウェアのテストに非常に役立ちます。
Alexander Mills

回答:


46

この回答はArray.forEach、ライブラリを使用せず、ネイティブバニラのみに基づいています。

基本的にsomething()3回呼び出すには、次を使用します。

[1,2,3].forEach(function(i) {
  something();
});

次の機能を検討します。

function something(){ console.log('something') }

発信者は

something
something
something

この質問を完了するために、something()それぞれ1、2、3回電話をかける方法を次に示します。

2017年です。ES6を使用できます。

[1,2,3].forEach(i => Array(i).fill(i).forEach(_ => {
  something()
}))

または古き良きES5では:

[1,2,3].forEach(function(i) {
  Array(i).fill(i).forEach(function() {
    something()
  })
}))

どちらの場合も、outpoutは

発信者は

something

something
something

something
something
something

(1回、2回、3回)


18
質問のこの部分を満たさないため、これは正しくありません。「something()を1、2、3回呼び出してください」このコードを使用するsomethingと、3回しか呼び出されません。6回呼び出す必要があります。
Ian Newson 2016

それから、それは良いより良いスタートかもしれないので、それがベストアンサーとして選ばれたと思います。
Vinyll 2017年

3
実際のインデックスのニーズに応じて、[...Array(i)]またはを使用することもできArray(i).fill()ます。
グイドブーマン2018

渡された引数に関心がない場合は、.forEach(something)
kvsm

85

ループを使うだけです:

var times = 10;
for(var i=0; i < times; i++){
    doSomething();
}

3
ありがとうございました!宣言型構文(ジャスミンなどと同様)を利用したい
BreakPhreak

そうですが、機能的なforループの宣言構文もはるかに優れています
Alexander Mills

69

ES6の代替案。

Array.from(Array(3)).forEach((x, i) => {
  something();
});

また、「それぞれ1、2、3回呼び出されるようにする」場合も同様です。

Array.from(Array(3)).forEach((x, i) => {
  Array.from(Array(i+1)).forEach((x, i2) => {
    console.log(`Something ${ i } ${ i2 }`)
  });
});

更新:

fill -arrays-with-undefinedから取得

これは、初期配列を作成するためのより最適化された方法のようです。@ felix-eveによって提案された2番目のパラメーターマップ関数を使用するように更新しました。

Array.from({ length: 3 }, (x, i) => {
  something();
});

3
すぐにスクリプトを作成しているだけでも大丈夫ですが、パフォーマンスはひどいので、集中的な再帰や本番環境では使用しないでください。
nverba 2017年

ES6を使用する場合は、forEach()の代わりにmap()を使用できます
Andy Ford

3
簡潔には、ゴールである(そして実際に、それがない場合であっても)、それを呼び出すのではなく、関数を渡す場合:Array.from(Array(3)).forEach(something)
kvsm

1
反応式のレンダリングでも動作します。
Josh Sharkey

4
Array.from()オプションの2番目のパラメーターmapFnがあります。これにより、配列の各要素に対してマップ関数を実行できるため、forEachを使用する必要はありません。あなただけ行うことができます:Array.from({length: 3}, () => somthing() )
フェリックス・イブ

19

アンダースコアについて言及したので:

想定するのfは、呼び出す関数です。

_.each([1,2,3], function (n) { _.times(n, f) });

トリックを行います。たとえばf = function (x) { console.log(x); }、を使用すると、コンソールが表示されます。 0 0 1 0 1 2


確かに、私はあなたが分離を望んでいると思いました。
ggozad

2
_(3).times(function(n){return n;});トリックを行う必要があります。こちらのドキュメントをご覧ください。
2014年

18

lodash

_.each([1, 2, 3], (item) => {
   doSomeThing(item);
});

//Or:
_.each([1, 2, 3], doSomeThing);

または、N回何かをしたい場合:

const N = 10;
_.times(N, () => {
   doSomeThing();
});

//Or shorter:
_.times(N, doSomeThing);

インストールについては、このリンクを参照しくださいlodash


12

配列とso メソッドfillundefined使用してすべてのアイテムを作成すると、機能mapする可能性があります。

Array.fill IEのサポートがない

Array(5).fill().map(()=>{ 
   // Do this 5 times:
   console.log(111) 
})


古い学校のリヴァーズループを使用する:

for( let i=5; i--; ){
   // Do this 5 times:
   console.log(222) 
}


念のため、uuid関数を5万実行して、uuidが複製されないようにしました。だから私はキックだけのためにトップループとボトムループをプロファイリングしました、私が愚かではないなら私はそのクローム開発ツールを使って通常のページロードの真ん中で実行しているだけです。newschool = 1st-5561.2ms 2nd-5426.8ms | oldschool = 1st-4966.3ms / 2nd-4929.0msストーリーのモラルは、uが10億以上の範囲にない場合、何かをするためにこれらの200、1k、10k回実行しても違いに気付くことはありません。誰かが私のように好奇心が強いかもしれないと考えました。
rifi2k

それは正しいですし、長年知られています。異なるアプローチは速度の利点のためではなく、古いブラウザのサポートのために提示されました。
vsync

2
明らかに、このスレッドを読むすべての人は、速度を比較するための例を提示しなかったことを知っています。私はたまたまそれらを使用して簡単なテストを実行し、将来の誰かが面白いと思うかもしれないという情報を共有したいと思いました。情報を表示し、とにかく数ミリ秒で終了するいくつかのことだけを行っているときにループの速度に汗を流さないように注意を払うだけの質問には答えていなかったので、私は本当に正しくありません。1年前の同じテストでは、ブラウザが常に変化するため、1つのテストが50%遅くなる可能性があるため、あまり知られていません。
rifi2k

9

次のように分解して同じことを行うこともできます

[...Array(3)].forEach( _ => console.log('do something'));

またはインデックスが必要な場合

[...Array(3)].forEach(( _, index) => console.log('do something'));

7

Underscorejsを使用できない場合は、自分で実装できます。NumberおよびStringプロトタイプに新しいメソッドをアタッチすると、次のようになります(ES6矢印関数を使用)。

// With String
"5".times( (i) => console.log("number "+i) );

// With number variable
var five = 5;
five.times( (i) => console.log("number "+i) );

// With number literal (parentheses required)
(5).times( (i) => console.log("number "+i) );

(任意の名前の)関数式を作成し、それにアクセスしたい(プロトタイプの)任意のプロパティ名に割り当てる必要があります。

var timesFunction = function(callback) {
  if (typeof callback !== "function" ) {
    throw new TypeError("Callback is not a function");
  } else if( isNaN(parseInt(Number(this.valueOf()))) ) {
    throw new TypeError("Object is not a valid number");
  }
  for (var i = 0; i < Number(this.valueOf()); i++) {
    callback(i);
  }
};

String.prototype.times = timesFunction;
Number.prototype.times = timesFunction;

1
プロトタイプにパッチを適用することの悪さを再調査する必要がありますが、通常は問題ありません
Alexander Mills

2

ラムダと呼ばれる素晴らしいライブラリがあります。これは、アンダースコアやロダッシュに似ていますが、より強力です。

const R = require('ramda');

R.call(R.times(() => {
    console.log('do something')
}), 5);

Ramdaには便利な機能がたくさん含まれています。Ramdaのドキュメントを参照


このライブラリは、モダンでエレガントなFPソリューションとして気に入っています。
momocow

1

配列の長さを使用して、タスクを何度も実行できます。

var arr = [1,2,3];

for(var i=0; i < arr.length; i++){
    doSomething();
}

または

 var arr = [1,2,3];

 do
 {


 }
 while (i++ < arr.length);

1

あなたは使うことができます

Array.forEach

例:

function logArrayElements(element, index, array) {  
    console.log("a[" + index + "] = " + element);  
}  
[2, 5, 9].forEach(logArrayElements)

またはjQueryで

$.each([52, 97], function(index, value) { 
  alert(index + ': ' + value); 
});

http://api.jquery.com/jQuery.each/


それは次のようになりますforEach:唯一のバージョン9からIEでサポートされてdeveloper.mozilla.org/en/JavaScript/Reference/Global_Objects/...
ブルーノ

1
times = function () {
    var length = arguments.length;
    for (var i = 0; i < length ; i++) {
        for (var j = 0; j < arguments[i]; j++) {
            dosomthing();
        }
    }
}

次のように呼び出すことができます。

times(3,4);
times(1,2,3,4);
times(1,3,5,7,9);

+1-これは、ネイティブのJavaScript機能を利用して、可変量のパラメーターを持つ関数を呼び出します。追加のライブラリは必要ありません。素敵なソリューション
RustyTheBoyRobot

1
// calls doSomething 42 times
Array( 42 ).join( "x" ).split( "" ).forEach( doSomething );

そして

// creates 42 somethings
var somethings = Array( 42 ).join( "x" ).split( "" ).map( () => buildSomething(); );

または(https://stackoverflow.com/a/20066663/275501経由)

Array.apply(null, {length: 42}).forEach( doSomething );

1
var times = [1,2,3];

for(var i = 0; i < times.length;  i++) {
  for(var j = 0; j < times[i];j++) {
     // do something
  }
}

jQueryの使用 .each()

$([1,2,3]).each(function(i, val) {
  for(var j = 0; j < val;j++) {
     // do something
  }
});

または

var x = [1,2,3];

$(x).each(function(i, val) {
  for(var j = 0; j < val;j++) {
     // do something
  }
});

編集

あなたは純粋なJSで以下のようにすることができます:

var times = [1,2,3];
times.forEach(function(i) {
   // do something
});

0

ネストされたループを使用するだけです(おそらく関数で囲まれています)

function times( fct, times ) {
  for( var i=0; i<times.length; ++i ) {
    for( var j=0; j<times[i]; ++j ) {
      fct();
    }
  }
}

次に、次のように呼び出します。

times( doSomething, [1,2,3] );

0

これらの答えはすべてうまくいっており、IMO @Andreasが最高ですが、JSでは何度も非同期で行う必要があります。その場合、非同期で対応できます。

http://caolan.github.io/async/docs.html#times

const async = require('async');

async.times(5, function(n, next) {
    createUser(n, function(err, user) {
        next(err, user);
    });
}, function(err, users) {
    // we should now have 5 users
});

これらの「時間」機能は、ほとんどのアプリケーションコードに非常に役立ちますが、テストには役立つはずです。


0
const loop (fn, times) => {
  if (!times) { return }
  fn()
  loop(fn, times - 1)
}

loop(something, 3)

0

与えられた関数something

function something() { console.log("did something") }

そしてtimesArrayプロトタイプに追加された新しいメソッド:

Array.prototype.times = function(f){
  for(v of this) 
    for(var _ of Array(v))
      f();
}

このコード:

[1,2,3].times(something)

これを出力します:

did something
did something
did something
did something
did something
did something

更新された質問(5年後)に答えると思いますが、これを配列で機能させるとどれほど便利なのでしょうか。効果はを呼び出すのと同じではありません[6].times(something)

for(_ of Array(6)) something();

(ただし、_ジャンク変数として使用すると、おそらくロダッシュまたはアンダースコアが使用されます)


1
ネイティブJSオブジェクトにカスタムメソッドを追加することは悪い習慣だと考えられています。
Lior Elrom、2018

letinのfor (let _ of Array(6)) something()ように使用して、少なくともの外でロダッシュを壊すのを防ぐことができます。
Ciro Santilli郝海东冠状病六四事件法轮功

0

Array.from(ES6)

function doSomthing() {
    ...
}

次のように使用します。

Array.from(Array(length).keys()).forEach(doSomthing);

または

Array.from({ length }, (v, i) => i).forEach(doSomthing);

または

// array start counting from 1
Array.from({ length }, (v, i) => ++i).forEach(doSomthing);

0

とを使用Array.from.forEachます。

let length = 5;
Array.from({length}).forEach((v, i) => {
  console.log(`#${i}`);
});


0

スプレッド演算子のようないくつかのES6構文を使用できると仮定すると、コレクション内のすべての数値の合計と同じ回数だけ何かを実行する必要があります。

この場合、時間が等しい場合[1,2,3]、合計回数は6回、つまり1 + 2 + 3になります。

/**
 * @param {number[]} times
 * @param {cb} function
 */
function doTimes(times, cb) {
  // Get the sum of all the times
  const totalTimes = times.reduce((acc, time) => acc + time);
  // Call the callback as many times as the sum
  [...Array(totalTimes)].map(cb);
}

doTimes([1,2,3], () => console.log('something'));
// => Prints 'something' 6 times

この投稿は、配列の構築と展開の背後にあるロジックが明らかでない場合に役立ちます


0

TypeScript実装:

実装方法String.timesNumber.times、タイプセーフでで動作する方法に興味のある方はthisArg、こちらをご覧ください。

declare global {
    interface Number {
        times: (callbackFn: (iteration: number) => void, thisArg?: any) => void;
    }
    interface String {
        times: (callbackFn: (iteration: number) => void, thisArg?: any) => void;
    }
}

Number.prototype.times = function (callbackFn, thisArg) {
    const num = this.valueOf()
    if (typeof callbackFn !== "function" ) {
        throw new TypeError("callbackFn is not a function")
    }
    if (num < 0) {
        throw new RangeError('Must not be negative')
    }
    if (!isFinite(num)) {
        throw new RangeError('Must be Finite')
    }
    if (isNaN(num)) {
        throw new RangeError('Must not be NaN')
    }

    [...Array(num)].forEach((_, i) => callbackFn.bind(thisArg, i + 1)())
    // Other elegant solutions
    // new Array<null>(num).fill(null).forEach(() => {})
    // Array.from({length: num}).forEach(() => {})
}

String.prototype.times = function (callbackFn, thisArg) {
    let num = parseInt(this.valueOf())
    if (typeof callbackFn !== "function" ) {
        throw new TypeError("callbackFn is not a function")
    }
    if (num < 0) {
        throw new RangeError('Must not be negative')
    }
    if (!isFinite(num)) {
        throw new RangeError('Must be Finite')
    }
    // num is NaN if `this` is an empty string 
    if (isNaN(num)) {
        num = 0
    }

    [...Array(num)].forEach((_, i) => callbackFn.bind(thisArg, i + 1)())
    // Other elegant solutions
    // new Array<null>(num).fill(null).forEach(() => {})
    // Array.from({length: num}).forEach(() => {})
}

いくつかの例を含むTypeScript Playgroundへのリンクはここにあります

投稿者:この記事を実装ソリューションアンドレアスベルイストロームvinyllOzay豆満江、&SeregPie

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.