Esiste un meccanismo per eseguire il ciclo x volte in ES6 (ECMAScript 6) senza variabili mutabili?


157

Il modo tipico di ripetere i xtempi in JavaScript è:

for (var i = 0; i < x; i++)
  doStuff(i);

Ma non voglio usare l' ++operatore o avere variabili mutabili. Quindi c'è un modo, in ES6, di ripetere i xtempi in un altro modo? Adoro il meccanismo di Ruby:

x.times do |i|
  do_stuff(i)
end

Qualcosa di simile in JavaScript / ES6? Potrei in qualche modo imbrogliare e creare il mio generatore:

function* times(x) {
  for (var i = 0; i < x; i++)
    yield i;
}

for (var i of times(5)) {
  console.log(i);
}

Certo che sto ancora usando i++. Almeno è fuori dalla vista :), ma spero che ci sia un meccanismo migliore in ES6.


3
Perché la variabile di controllo dell'anello mutabile è un problema? Solo un principio?
Doldt,

1
@doldt - Sto cercando di insegnare JavaScript, ma sto sperimentando di ritardare il concetto di variabili mutabili fino a dopo
a.

5
Stiamo diventando davvero fuori tema, ma sei sicuro che passare a generatori ES6 (o qualsiasi altro nuovo concetto di alto livello) sia una buona idea prima che imparino a conoscere le variabili mutabili? :)
doldt

5
@doldt - forse sto sperimentando. Adottare un approccio linguistico funzionale a JavaScript.
a.

Usa let per dichiarare quella variabile nel loop. Il suo scopo termina con il ciclo.
ncmathsadist,

Risposte:


156

OK!

Il codice seguente è scritto usando la sintassi ES6 ma potrebbe essere facilmente scritto in ES5 o anche meno. ES6 non è un requisito per creare un "meccanismo per eseguire il ciclo x volte"


Se non è necessario l'iteratore nel callback , questa è l'implementazione più semplice

const times = x => f => {
  if (x > 0) {
    f()
    times (x - 1) (f)
  }
}

// use it
times (3) (() => console.log('hi'))

// or define intermediate functions for reuse
let twice = times (2)

// twice the power !
twice (() => console.log('double vision'))

Se hai bisogno dell'iteratore , puoi usare una funzione interna denominata con un parametro contatore per iterare per te

const times = n => f => {
  let iter = i => {
    if (i === n) return
    f (i)
    iter (i + 1)
  }
  return iter (0)
}

times (3) (i => console.log(i, 'hi'))


Smetti di leggere qui se non ti piace imparare più cose ...

Ma qualcosa dovrebbe sentirsi fuori di quelli ...

  • le ifdichiarazioni di singoli rami sono brutte - cosa succede sull'altro ramo?
  • dichiarazioni / espressioni multiple negli organi della funzione - le preoccupazioni procedurali vengono mescolate?
  • implicitamente restituito undefined- indicazione della funzione impura, con effetti collaterali

"Non c'è un modo migliore?"

C'è. Rivisitiamo innanzitutto la nostra implementazione iniziale

// times :: Int -> (void -> void) -> void
const times = x => f => {
  if (x > 0) {
    f()               // has to be side-effecting function
    times (x - 1) (f)
  }
}

Certo, è semplice, ma nota come chiamiamo f()e non ci facciamo nulla. Questo limita davvero il tipo di funzione che possiamo ripetere più volte. Anche se abbiamo l'iteratore disponibile, f(i)non è molto più versatile.

E se iniziassimo con un migliore tipo di procedura di ripetizione delle funzioni? Forse qualcosa che sfrutta meglio input e output.

Ripetizione di funzioni generiche

// repeat :: forall a. Int -> (a -> a) -> a -> a
const repeat = n => f => x => {
  if (n > 0)
    return repeat (n - 1) (f) (f (x))
  else
    return x
}

// power :: Int -> Int -> Int
const power = base => exp => {
  // repeat <exp> times, <base> * <x>, starting with 1
  return repeat (exp) (x => base * x) (1)
}

console.log(power (2) (8))
// => 256

Sopra, abbiamo definito una repeatfunzione generica che accetta un input aggiuntivo che viene utilizzato per avviare l'applicazione ripetuta di una singola funzione.

// repeat 3 times, the function f, starting with x ...
var result = repeat (3) (f) (x)

// is the same as ...
var result = f(f(f(x)))

Implementazione timesconrepeat

Bene, adesso è facile; quasi tutto il lavoro è già fatto.

// repeat :: forall a. Int -> (a -> a) -> a -> a
const repeat = n => f => x => {
  if (n > 0)
    return repeat (n - 1) (f) (f (x))
  else
    return x
}

// times :: Int -> (Int -> Int) -> Int 
const times = n=> f=>
  repeat (n) (i => (f(i), i + 1)) (0)

// use it
times (3) (i => console.log(i, 'hi'))

Poiché la nostra funzione prende icome input e ritorna i + 1, questo funziona efficacemente come iteratore al quale passiamo fogni volta.

Abbiamo risolto anche il nostro elenco puntato di problemi

  • Niente più brutte ifdichiarazioni a ramo singolo
  • I corpi a espressione singola indicano preoccupazioni ben separate
  • Non più inutile, implicitamente restituito undefined

Operatore virgola JavaScript, il

Nel caso in cui tu abbia problemi a vedere come funziona l'ultimo esempio, dipende dalla tua consapevolezza di uno dei più antichi assi di battaglia di JavaScript; l' operatore virgola : in breve, valuta le espressioni da sinistra a destra e restituisce il valore dell'ultima espressione valutata

(expr1 :: a, expr2 :: b, expr3 :: c) :: c

Nel nostro esempio sopra, sto usando

(i => (f(i), i + 1))

che è solo un modo sintetico di scrivere

(i => { f(i); return i + 1 })

Ottimizzazione delle chiamate di coda

Per quanto sexy siano le implementazioni ricorsive, a questo punto sarebbe irresponsabile per me consigliarle dato che nessuna VM JavaScript posso pensare di supportare la corretta eliminazione delle chiamate di coda - Babele era solita traspilarla, ma è stata "rotta; reimplementerà "status da oltre un anno.

repeat (1e6) (someFunc) (x)
// => RangeError: Maximum call stack size exceeded

Pertanto, dovremmo rivisitare la nostra implementazione repeatper renderla impilabile.

Il codice qui sotto fa utilizzare le variabili mutabili ne xma nota che tutte le mutazioni sono localizzate alla repeatfunzione - nessun cambiamento di stato (mutazioni) sono visibili dall'esterno della funzione

// repeat :: Int -> (a -> a) -> (a -> a)
const repeat = n => f => x =>
  {
    let m = 0, acc = x
    while (m < n)
      (m = m + 1, acc = f (acc))
    return acc
  }

// inc :: Int -> Int
const inc = x =>
  x + 1

console.log (repeat (1e8) (inc) (0))
// 100000000

Molti di voi diranno "ma non è funzionale!" - Lo so, rilassati. Siamo in grado di implementare uno stile loop/ recurinterfaccia Clojure per il looping dello spazio costante usando espressioni pure ; nessuna di queste whilecose.

Qui riusciamo ad astrarre whilecon la nostra loopfunzione: cerca un recurtipo speciale per mantenere il loop in esecuzione. Quando recursi incontra un non tipo, il ciclo è terminato e viene restituito il risultato del calcolo

const recur = (...args) =>
  ({ type: recur, args })
  
const loop = f =>
  {
    let acc = f ()
    while (acc.type === recur)
      acc = f (...acc.args)
    return acc
  }

const repeat = $n => f => x =>
  loop ((n = $n, acc = x) =>
    n === 0
      ? acc
      : recur (n - 1, f (acc)))
      
const inc = x =>
  x + 1

const fibonacci = $n =>
  loop ((n = $n, a = 0, b = 1) =>
    n === 0
      ? a
      : recur (n - 1, b, a + b))
      
console.log (repeat (1e7) (inc) (0)) // 10000000
console.log (fibonacci (100))        // 354224848179262000000


24
Sembra troppo complicato (sono particolarmente confuso con g => g(g)(x)). C'è un vantaggio da una funzione di ordine superiore rispetto a una di primo ordine, come nella mia soluzione?
Pavlo,

1
@naomik: grazie per aver dedicato del tempo a pubblicare un link. molto apprezzato.
Pineda,

1
@ AlfonsoPérez Apprezzo l'osservazione. Vedrò se riesco a lavorare un piccolo suggerimento lì da qualche parte ^ _ ^
Grazie

1
@naomik Addio TCO ! Sono devastato

10
Sembra che questa risposta sia accettata e valutata perché deve aver richiesto molto impegno, ma non credo sia una buona risposta. La risposta corretta alla domanda è "no". È utile elencare una soluzione alternativa come hai fatto tu, ma subito dopo affermi che esiste un modo migliore. Perché non metti solo quella risposta e rimuovi quella peggiore in alto? Perché stai spiegando gli operatori virgola? Perché porti Clojure? Perché, in generale, così tante tangenti per una domanda con una risposta di 2 caratteri? Le domande semplici non sono solo una piattaforma per gli utenti di fare una presentazione su alcuni fatti di programmazione.
Timofey 'Sasha' Kondrashov,

267

Utilizzo dell'operatore ES2015 Spread :

[...Array(n)].map()

const res = [...Array(10)].map((_, i) => {
  return i * 10;
});

// as a one liner
const res = [...Array(10)].map((_, i) => i * 10);

O se non hai bisogno del risultato:

[...Array(10)].forEach((_, i) => {
  console.log(i);
});

// as a one liner
[...Array(10)].forEach((_, i) => console.log(i));

O usando l' operatore ES2015 Array.from :

Array.from(...)

const res = Array.from(Array(10)).map((_, i) => {
  return i * 10;
});

// as a one liner
const res = Array.from(Array(10)).map((_, i) => i * 10);

Nota che se hai solo bisogno di ripetere una stringa puoi usare String.prototype.repeat .

console.log("0".repeat(10))
// 0000000000

26
Meglio:Array.from(Array(10), (_, i) => i*10)
Bergi,

6
Questa dovrebbe essere la risposta migliore. Quindi ES6! Molto fantastico!
Gergely Fehérvári,

3
Se non hai bisogno dell'iteratore (i), puoi escludere sia la chiave che il valore per farlo:[...Array(10)].forEach(() => console.log('looping 10 times');
Sterling Bourne,

9
Quindi allochi l' intero array di N elementi solo per buttarlo via?
Kugel,

2
Qualcuno ha affrontato il precedente commento di Kugel? Mi chiedevo la stessa cosa
Arman il

37
for (let i of Array(100).keys()) {
    console.log(i)
}

Funziona, quindi è fantastico! Ma è un po 'brutto nel senso che è necessario un lavoro extra e questo non è ciò per cui Arrayvengono utilizzate le chiavi.
a.

@a. infatti. Ma non sono sicuro che ci sia un sinonimo di haskell [0..x]in JS più conciso che nella mia risposta.
zerkms,

potresti avere ragione sul fatto che non c'è niente di più conciso di questo.
a.

OK, capisco perché funziona a causa delle differenze tra Array.prototype.keyse Object.prototype.keys, ma a prima vista è confuso.
Mark Reed,

1
@cchamberlain con TCO in ES2015 (non implementato da nessuna parte però?) potrebbe essere il meno preoccupante, ma in effetti :-)
zerkms

29

Penso che la soluzione migliore sia usare let:

for (let i=0; i<100; i++) 

Ciò creerà una nuova ivariabile (mutabile) per ogni valutazione del corpo e assicurerà che iviene modificata solo nell'espressione dell'incremento nella sintassi del ciclo, non da nessun'altra parte.

Potrei in qualche modo imbrogliare e creare il mio generatore. Almeno i++è fuori dalla vista :)

Questo dovrebbe essere abbastanza imo. Anche nei linguaggi puri tutte le operazioni (o almeno i loro interpreti) sono costruite da primitivi che usano la mutazione. Finché è correttamente mirato, non riesco a vedere cosa c'è che non va.

Dovresti stare bene con

function* times(n) {
  for (let i = 0; i < x; i++)
    yield i;
}
for (const i of times(5))
  console.log(i);

Ma non voglio usare l' ++operatore o avere variabili mutabili.

Quindi la tua unica scelta è usare la ricorsione. Puoi definire quella funzione del generatore anche senza un mutabile i:

function* range(i, n) {
  if (i >= n) return;
  yield i;
  return yield* range(i+1, n);
}
times = (n) => range(0, n);

Ma questo mi sembra eccessivo e potrebbe avere problemi di prestazioni (poiché l'eliminazione della coda non è disponibile per return yield*).


1
Mi piace questa opzione: bella e semplice!
DanV,

2
Questo è semplice e preciso e non alloca un array come molte risposte sopra
Kugel

@Kugel Il secondo potrebbe allocare in pila, però
Bergi

Un buon punto non è sicuro se l'ottimizzazione delle chiamate in coda funzionerà qui @Bergi
Kugel



11

Risposta: 09 dicembre 2015

Personalmente, ho trovato la risposta accettata sia concisa (buona) che concisa (cattiva). Apprezzare questa affermazione potrebbe essere soggettivo, quindi leggi questa risposta e vedi se sei d'accordo o in disaccordo

L'esempio fornito nella domanda era qualcosa di simile a Ruby:

x.times do |i|
  do_stuff(i)
end

Esprimerlo in JS usando di seguito consentirebbe:

times(x)(doStuff(i));

Ecco il codice:

let times = (n) => {
  return (f) => {
    Array(n).fill().map((_, i) => f(i));
  };
};

Questo è tutto!

Esempio di utilizzo semplice:

let cheer = () => console.log('Hip hip hooray!');

times(3)(cheer);

//Hip hip hooray!
//Hip hip hooray!
//Hip hip hooray!

In alternativa, seguendo gli esempi della risposta accettata:

let doStuff = (i) => console.log(i, ' hi'),
  once = times(1),
  twice = times(2),
  thrice = times(3);

once(doStuff);
//0 ' hi'

twice(doStuff);
//0 ' hi'
//1 ' hi'

thrice(doStuff);
//0 ' hi'
//1 ' hi'
//2 ' hi'

Nota a margine: definizione di una funzione di intervallo

Una domanda simile / correlata, che utilizza costrutti di codice fondamentalmente molto simili, potrebbe essere: esiste una comoda funzione Range in JavaScript (core), qualcosa di simile alla funzione range underscore.

Crea un array con n numeri, a partire da x

Sottolineare

_.range(x, x + n)

ES2015

Coppia di alternative:

Array(n).fill().map((_, i) => x + i)

Array.from(Array(n), (_, i) => x + i)

Demo usando n = 10, x = 1:

> Array(10).fill().map((_, i) => i + 1)
// [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ]

> Array.from(Array(10), (_, i) => i + 1)
// [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ]

In un test rapido ho eseguito, con ciascuno dei precedenti in esecuzione un milione di volte ciascuno utilizzando la nostra soluzione e la funzione doStuff, il primo approccio (Array (n) .fill ()) si è rivelato leggermente più veloce.


8
Array(100).fill().map((_,i)=> console.log(i) );

Questa versione soddisfa i requisiti dell'OP per l'immutabilità. Considera anche l'utilizzo reduceinvece di map dipendere dal tuo caso d'uso.

Questa è anche un'opzione se non ti dispiace una piccola mutazione nel tuo prototipo.

Number.prototype.times = function(f) {
   return Array(this.valueOf()).fill().map((_,i)=>f(i));
};

Ora possiamo farlo

((3).times(i=>console.log(i)));

+1 a arcseldon per il .fillsuggerimento.


Votato verso il basso, poiché il metodo di riempimento non è supportato in IE o Opera o PhantomJS
morhook,

8

Ecco un'altra buona alternativa:

Array.from({ length: 3}).map(...);

Preferibilmente, come sottolineato da @Dave Morse nei commenti, puoi anche sbarazzarti della mapchiamata, usando il secondo parametro della Array.fromfunzione in questo modo:

Array.from({ length: 3 }, () => (...))


2
Questa dovrebbe essere la risposta accettata! Un piccolo suggerimento: con Array.from ottieni già la funzionalità simile a una mappa di cui hai bisogno gratuitamente: Array.from({ length: label.length }, (_, i) => (...)) questo consente di salvare la creazione di un array temporaneo vuoto solo per dare il via a una chiamata alla mappa.
Dave Morse,

7

Non qualcosa che vorrei insegnare (o mai usare nel mio codice), ma ecco una soluzione degna di codegolf senza mutare una variabile, non è necessario ES6:

Array.apply(null, {length: 10}).forEach(function(_, i){
    doStuff(i);
})

Più una cosa interessante di prova di concetto che una risposta utile, davvero.


Non potrebbe Array.apply(null, {length: 10})essere giusto Array(10)?
Pavlo,

1
@Pavlo, in realtà, no. Array (10) creerebbe un array di lunghezza 10, ma senza alcuna chiave definita in esso, il che rende il costrutto forEach non utilizzabile in questo caso. Ma in effetti può essere semplificato se non si utilizza per ciascuno, vedere la risposta di zerkms (che utilizza ES6!).
Doldt,

creativo @doldt, ma sto cercando qualcosa di insegnabile e semplice.
a.

5

Sono in ritardo alla festa, ma poiché questa domanda si presenta spesso nei risultati di ricerca, vorrei solo aggiungere una soluzione che considero la migliore in termini di leggibilità pur non essendo lunga (che è l'ideale per qualsiasi IMO di base di codice) . Muta, ma farei questo compromesso per i principi dei KISS.

let times = 5
while( times-- )
    console.log(times)
// logs 4, 3, 2, 1, 0

3
Grazie per essere la voce della ragione in quello che posso solo descrivere come una festa fetish lambda di ordine superiore. Anch'io sono finito su questa domanda e risposta seguendo un innocuo primo colpo sul percorso di Google e ho rapidamente dissacrato la mia sanità mentale dalla maggior parte delle risposte qui. Il tuo è il primo nell'elenco che considererei una soluzione semplice a un problema semplice.
Martin Devillers,

L'unico problema con questo è che è un po 'controintuitivo se si desidera utilizzare la timesvariabile all'interno del ciclo. Forse countdownsarebbe una denominazione migliore. Altrimenti, la risposta più pulita e chiara sulla pagina.
Tony Brasunas,

3

Dopo tutto, in ES6 non esiste alcun meccanismo simile al timesmetodo di Ruby . Ma puoi evitare la mutazione usando la ricorsione:

let times = (i, cb, l = i) => {
  if (i === 0) return;

  cb(l - i);
  times(i - 1, cb, l);
}

times(5, i => doStuff(i));

Demo: http://jsbin.com/koyecovano/1/edit?js,console


Mi piace questo approccio, adoro la ricorsione. Ma mi piacerebbe qualcosa di più semplice per mostrare i nuovi loop degli utenti JavaScript.
a.

3

Se sei disposto a utilizzare una libreria, c'è anche lodash_.times o trattino basso_.times :

_.times(x, i => {
   return doStuff(i)
})

Nota che questo restituisce una serie di risultati, quindi è molto più simile a questo rubino:

x.times.map { |i|
  doStuff(i)
}

2

Nel paradigma funzionale repeatè di solito una funzione ricorsiva infinita. Per usarlo abbiamo bisogno di una valutazione pigra o di uno stile di passaggio di continuazione.

Ripetizione della funzione valutata pigra

const repeat = f => x => [x, () => repeat(f) (f(x))];
const take = n => ([x, f]) => n === 0 ? x : take(n - 1) (f());

console.log(
  take(8) (repeat(x => x * 2) (1)) // 256
);

Uso un thunk (una funzione senza argomenti) per ottenere una valutazione pigra in Javascript.

Ripetizione di funzioni con stile di passaggio di continuazione

const repeat = f => x => [x, k => k(repeat(f) (f(x)))];
const take = n => ([x, k]) => n === 0 ? x : k(take(n - 1));

console.log(
  take(8) (repeat(x => x * 2) (1)) // 256
);

All'inizio CPS fa un po 'paura. Tuttavia, segue sempre lo stesso schema: L'ultimo argomento è la continuazione (una funzione), che richiama proprio corpo: k => k(...). Si noti che CPS capovolge l'applicazione, ovvero take(8) (repeat...)diventa k(take(8)) (...)dove kviene parzialmente applicato repeat.

Conclusione

Separando la ripetizione ( repeat) dalla condizione di terminazione ( take) otteniamo flessibilità - separazione delle preoccupazioni fino alla sua fine amara: D


1

Vantaggi di questa soluzione

  • Più semplice da leggere / utilizzare (imo)
  • Il valore di ritorno può essere utilizzato come somma o semplicemente ignorato
  • Versione semplice es6, anche collegamento alla versione TypeScript del codice

Svantaggi - Mutazione. Essere interni solo non mi interessa, forse alcuni altri no.

Esempi e codice

times(5, 3)                       // 15    (3+3+3+3+3)

times(5, (i) => Math.pow(2,i) )   // 31    (1+2+4+8+16)

times(5, '<br/>')                 // <br/><br/><br/><br/><br/>

times(3, (i, count) => {          // name[0], name[1], name[2]
    let n = 'name[' + i + ']'
    if (i < count-1)
        n += ', '
    return n
})

function times(count, callbackOrScalar) {
    let type = typeof callbackOrScalar
    let sum
    if (type === 'number') sum = 0
    else if (type === 'string') sum = ''

    for (let j = 0; j < count; j++) {
        if (type === 'function') {
            const callback = callbackOrScalar
            const result = callback(j, count)
            if (typeof result === 'number' || typeof result === 'string')
                sum = sum === undefined ? result : sum + result
        }
        else if (type === 'number' || type === 'string') {
            const scalar = callbackOrScalar
            sum = sum === undefined ? scalar : sum + scalar
        }
    }
    return sum
}

Versione TypeScipt
https://codepen.io/whitneyland/pen/aVjaaE?editors=0011


0

affrontando l'aspetto funzionale:

function times(n, f) {
    var _f = function (f) {
        var i;
        for (i = 0; i < n; i++) {
            f(i);
        }
    };
    return typeof f === 'function' && _f(f) || _f;
}
times(6)(function (v) {
    console.log('in parts: ' + v);
});
times(6, function (v) {
    console.log('complete: ' + v);
});

5
"affrontare l'aspetto funzionale" e quindi usare un ciclo imperativo con un mutevole i. Qual è la ragione per usare anche timessu vecchio normale forallora?
zerkms,

riutilizzare come var twice = times(2);.
Nina Scholz,

Quindi perché non usarlo solo fordue volte?
zerkms,

non ho paura di usare per. la domanda era qualcosa per non usare un variabele. ma il risultato è sempre una specie di cache nota come variabile.
Nina Scholz,

1
"era qualcosa da non usare un variabele" --- e lo usi ancora - i++. Non è ovvio come avvolgere qualcosa di inaccettabile in una funzione lo renda migliore.
zerkms,

0

Generatori? Ricorsione? Perché così tanto odiare la mutatina? ;-)

Se è accettabile fintanto che lo "nascondiamo", accetta semplicemente l'uso di un operatore unario e possiamo semplificare le cose :

Number.prototype.times = function(f) { let n=0 ; while(this.valueOf() > n) f(n++) }

Proprio come nel rubino:

> (3).times(console.log)
0
1
2

2
Pollice in alto: "Perché tanto odiare la mutatina?"
Sarreph,

1
Pollice in su per semplicità, pollice in giù per diventare un po 'troppo rubino con il monkeypatch. Di 'di no a quelle cattive scimmie cattive.
sig.

1
@mrm è questo "patching di scimmie", non è solo un caso di estensione? Abbraccia e prolunga :)
conny

No. L'aggiunta di funzioni a Number (o String o Array o qualsiasi altra classe che non hai creato) sono, per definizione, polifilloli o patch di scimmie - e persino i polifilloli non sono raccomandati. Leggi le definizioni di "patch scimmia", "polyfill" e un'alternativa consigliata, "ponyfill". Questo è ciò che vuoi.
sig.

Per estendere il numero si dovrebbe fare: la classe SuperNumber estende il numero {times (fn) {for (let i = 0; i <this; i ++) {fn (i); }}}
Alexander,

0

Ho racchiuso la risposta di @Tieme con una funzione di supporto.

In TypeScript:

export const mapN = <T = any[]>(count: number, fn: (...args: any[]) => T): T[] => [...Array(count)].map((_, i) => fn())

Ora puoi eseguire:

const arr: string[] = mapN(3, () => 'something')
// returns ['something', 'something', 'something']

0

Ho fatto questo:

function repeat(func, times) {
    for (var i=0; i<times; i++) {
        func(i);
    }
}

Uso:

repeat(function(i) {
    console.log("Hello, World! - "+i);
}, 5)

/*
Returns:
Hello, World! - 0
Hello, World! - 1
Hello, World! - 2
Hello, World! - 3
Hello, World! - 4
*/

La ivariabile restituisce il numero di volte che è stata ripetuta in loop, utile se è necessario precaricare una quantità x di immagini.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.