Czy w Javascript można łatwo napisać coś takiego:
[1,2,3].times do {
something();
}
Może jakakolwiek biblioteka obsługująca podobną składnię?
Aktualizacja: wyjaśnienie - chciałbym something()
nazywać się odpowiednio 1,2 i 3 razy dla każdej iteracji elementu tablicy
javascript
jquery
underscore.js
BreakPhreak
źródło
źródło
Odpowiedzi:
Ta odpowiedź opiera się
Array.forEach
, bez żadnej biblioteki, tylko na natywnej wanilii .Aby zadzwonić w zasadzie
something()
3 razy, użyj:[1,2,3].forEach(function(i) { something(); });
biorąc pod uwagę następującą funkcję:
function something(){ console.log('something') }
Wylot będzie
Aby odpowiedzieć na to pytanie, oto sposób wykonania połączenia odpowiednio
something()
1, 2 i 3 razy:Jest rok 2017, możesz użyć ES6:
[1,2,3].forEach(i => Array(i).fill(i).forEach(_ => { something() }))
lub w starym dobrym ES5:
[1,2,3].forEach(function(i) { Array(i).fill(i).forEach(function() { something() }) }))
W obu przypadkach wylew będzie
Wylot będzie
(raz, potem dwa razy, potem 3 razy)
źródło
something
jest wywoływane tylko 3 razy, należy go wywołać 6 razy.[...Array(i)]
lubArray(i).fill()
, w zależności od potrzeb dla rzeczywistych indeksów..forEach(something)
Po prostu użyj pętli:
var times = 10; for(var i=0; i < times; i++){ doSomething(); }
źródło
Możliwa alternatywa ES6.
Array.from(Array(3)).forEach((x, i) => { something(); });
A jeśli chcesz, aby było to „nazwane odpowiednio 1,2 i 3 razy”.
Array.from(Array(3)).forEach((x, i) => { Array.from(Array(i+1)).forEach((x, i2) => { console.log(`Something ${ i } ${ i2 }`) }); });
Aktualizacja:
Zaczerpnięte z fill-arrays-with-undefined
Wydaje się, że jest to bardziej zoptymalizowany sposób tworzenia początkowej tablicy, zaktualizowałem to również, aby używać drugiej funkcji mapy parametrów sugerowanej przez @ felix-eve.
Array.from({ length: 3 }, (x, i) => { something(); });
źródło
Array.from(Array(3)).forEach(something)
Array.from()
ma opcjonalny drugi parametrmapFn
, który pozwala na wykonanie funkcji mapowania na każdym elemencie tablicy, więc nie ma potrzeby używania forEach. Możesz po prostu zrobić:Array.from({length: 3}, () => somthing() )
Skoro wspominasz o podkreśleniu:
Zakładając, że
f
jest to funkcja, którą chcesz wywołać:_.each([1,2,3], function (n) { _.times(n, f) });
da rade. Na przykład za pomocą
f = function (x) { console.log(x); }
dostaniesz na konsoli:0 0 1 0 1 2
źródło
_(3).times(function(n){return n;});
powinien załatwić sprawę. Zobacz dokumentację tutaj.Z lodash :
_.each([1, 2, 3], (item) => { doSomeThing(item); }); //Or: _.each([1, 2, 3], doSomeThing);
Lub jeśli chcesz coś zrobić N razy :
const N = 10; _.times(N, () => { doSomeThing(); }); //Or shorter: _.times(N, doSomeThing);
Skorzystaj z tego łącza, aby
lodash
zainstalowaćźródło
Utwórz tablicę i
fill
wszystkie elementy za pomocą metodyundefined
somap
mogą działać:// run 5 times: Array(5).fill().map((item, i)=>{ console.log(i) // print index })
Jeśli chcesz, aby powyższe stwierdzenie było bardziej „deklaratywne”, moje obecnie oparte na opiniach rozwiązanie byłoby następujące:
Pokaż fragment kodu
const iterate = times => callback => Array(times).fill().map((n,i) => callback(i)) iterate(3)(console.log)
Korzystanie ze starej (odwrotnej) pętli:
// run 5 times: for( let i=5; i--; ) console.log(i)
Lub jako deklaratywne „podczas” :
Pokaż fragment kodu
const times = count => callback => { while(count--) callback(count) } times(3)(console.log)
źródło
Możesz również zrobić to samo z destrukturyzacją w następujący sposób
[...Array(3)].forEach( _ => console.log('do something'));
lub jeśli potrzebujesz index
[...Array(3)].forEach(( _, index) => console.log('do something'));
źródło
Jeśli nie możesz użyć Underscorejs, możesz to zaimplementować samodzielnie. Dołączając nowe metody do prototypów Number i String, można to zrobić w następujący sposób (używając funkcji strzałek 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) );
Musisz po prostu utworzyć wyrażenie funkcyjne (o dowolnej nazwie) i przypisać je do dowolnej nazwy właściwości (na prototypach), do której chcesz uzyskać dostęp jako:
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;
źródło
Istnieje fantastyczna biblioteka o nazwie Ramda, która jest podobna do Underscore i Lodash, ale ma większe możliwości.
const R = require('ramda'); R.call(R.times(() => { console.log('do something') }), 5);
Ramda zawiera wiele przydatnych funkcji. Zobacz dokumentację Ramda
źródło
Możesz użyć length of array do wykonania zadania, ile razy.
var arr = [1,2,3]; for(var i=0; i < arr.length; i++){ doSomething(); }
lub
var arr = [1,2,3]; do { } while (i++ < arr.length);
źródło
możesz użyć
Array.forEach
przykład:
function logArrayElements(element, index, array) { console.log("a[" + index + "] = " + element); } [2, 5, 9].forEach(logArrayElements)
lub z jQuery
$.each([52, 97], function(index, value) { alert(index + ': ' + value); });
http://api.jquery.com/jQuery.each/
źródło
forEach
jest obsługiwany tylko w IE od wersji 9: developer.mozilla.org/en/JavaScript/Reference/Global_Objects/ ...times = function () { var length = arguments.length; for (var i = 0; i < length ; i++) { for (var j = 0; j < arguments[i]; j++) { dosomthing(); } } }
Możesz to nazwać tak:
times(3,4); times(1,2,3,4); times(1,3,5,7,9);
źródło
// calls doSomething 42 times Array( 42 ).join( "x" ).split( "" ).forEach( doSomething );
i
// creates 42 somethings var somethings = Array( 42 ).join( "x" ).split( "" ).map( () => buildSomething(); );
lub (przez https://stackoverflow.com/a/20066663/275501 )
Array.apply(null, {length: 42}).forEach( doSomething );
źródło
var times = [1,2,3]; for(var i = 0; i < times.length; i++) { for(var j = 0; j < times[i];j++) { // do something } }
Korzystanie z jQuery
.each()
$([1,2,3]).each(function(i, val) { for(var j = 0; j < val;j++) { // do something } });
LUB
var x = [1,2,3]; $(x).each(function(i, val) { for(var j = 0; j < val;j++) { // do something } });
EDYTOWAĆ
Możesz zrobić jak poniżej z czystym JS:
var times = [1,2,3]; times.forEach(function(i) { // do something });
źródło
Po prostu użyj zagnieżdżonej pętli (może być zawarta w funkcji)
function times( fct, times ) { for( var i=0; i<times.length; ++i ) { for( var j=0; j<times[i]; ++j ) { fct(); } } }
Następnie nazwij to tak:
times( doSomething, [1,2,3] );
źródło
Wszystkie te odpowiedzi są dobre i dobre, a IMO @Andreas jest najlepsze, ale wiele razy w JS musimy robić rzeczy asynchronicznie, w takim przypadku async obejmuje:
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 });
Te funkcje „czasów” nie są zbyt przydatne w przypadku większości kodu aplikacji, ale powinny być przydatne do testowania.
źródło
const loop (fn, times) => { if (!times) { return } fn() loop(fn, times - 1) } loop(something, 3)
źródło
Biorąc pod uwagę funkcję
something
:function something() { console.log("did something") }
times
DoArray
prototypu dodano nową metodę :Array.prototype.times = function(f){ for(v of this) for(var _ of Array(v)) f(); }
Ten kod:
[1,2,3].times(something)
Wyprowadza to:
Która, jak sądzę, odpowiada na twoje zaktualizowane pytanie (5 lat później), ale zastanawiam się, jak przydatne jest posiadanie tej pracy na tablicy? Czy efekt nie byłby taki sam jak wywołanie
[6].times(something)
, które z kolei można zapisać jako:for(_ of Array(6)) something();
(chociaż użycie
_
zmiennej jako śmieciowej prawdopodobnie spowoduje przebicie lodash lub podkreślenie, jeśli jej używasz)źródło
let
jak w,for (let _ of Array(6)) something()
aby zapobiec bicie lodash poza przynajmniej przez.Array.from (ES6)
function doSomthing() { ... }
Użyj go w ten sposób:
Array.from(Array(length).keys()).forEach(doSomthing);
Lub
Array.from({ length }, (v, i) => i).forEach(doSomthing);
Lub
// array start counting from 1 Array.from({ length }, (v, i) => ++i).forEach(doSomthing);
źródło
Korzystanie
Array.from
i.forEach
.let length = 5; Array.from({length}).forEach((v, i) => { console.log(`#${i}`); });
źródło
Zakładając, że możemy użyć jakiejś składni ES6, takiej jak operator spreadu, będziemy chcieli zrobić coś tyle razy, ile będzie suma wszystkich liczb w kolekcji.
W tym przypadku, jeśli czasy są równe
[1,2,3]
, całkowita liczba razy wyniesie 6, tj. 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
Ten post powinien być pomocny, jeśli logika stojąca za konstruowaniem i rozpowszechnianiem tablicy nie jest oczywista.
źródło
Implementacja TypeScript:
Dla tych z Was, którzy są zainteresowani, jak wdrożyć
String.times
iNumber.times
w sposób, który jest typu bezpieczne i współpracuje zthisArg
, tutaj ya go: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(() => {}) }
Link do Playground TypeScript z kilkoma przykładami można znaleźć tutaj
W tym poście zastosowano rozwiązania opublikowane przez: Andreas Bergström , vinyll , Ozay Duman i SeregPie
źródło