En la pràctica 1 d'aquest mòdul hem estudiat una estructura de control repetitiva: els bucles for. Aquesta estructura té la particularitat que el nombre d'iteracions a efectuar és un valor constant i que s'ha de conèixer des d'un principi.

Hi ha altres ocasions en què també s'ha d'aplicar estructures de control iteratives, però, sense saber inicialment, quin serà el nombre de repeticions a efectuar. Per a aquests casos existeix l'estructura de control while.

La funció d'un bucle while és repetir un bloc accions mentre sigui certa una determinada condició.

Evidentment, la condició s'haurà de modificar dins de les accions a repetir i en alguna ocasió futura haurà de canviar el seu valor a fals, en cas contrari, si la condició mai canviés, es produiria un bucle sense fi que provocaria un error del programa.

En aquesta pràctica veurem la utilització de la sentència while, de la seva variant do ... while i altres conceptes associats, conjuntament amb exemples senzills d'aplicació.


  Elements JavaScript en aquest capítol.
Sentència while() : executa un bloc de codi mentre una condició sigui certa, és possible que no s'executi cap vegada..
Sentència do ... while() : executa un bloc de codi mentre una condició sigui certa, almenys una vegada.
Sentència continue : provoca que es torni a executar des de l'inici el bloc de codi.
Sentència break : provoca que finalitzi l'execució repetitiva del bloc de codi, independentment del valor de la condició.
Mètode parseInt(cadena) : Converteix en valor numèric enter el contingut de cadena. Si no es pot, retorna NaN (Not a Number).
Mètode isNaN(valor) : Retorna true si el contingut de valor no és numèric, en cas contrari, retorna false.
 
1.-
La mitjana aritmètica. Bucles while().
La sintaxi genèrica de while és la següent:

      while(condició)
      {
        ..instruccions..
        [break]
        ..instruccions..
        [continue]
        ..instruccions..
      }


Aquesta estructura de control s'ha de llegir de la següent forma:
            Mentre la condició sigui certa fer ...

Els elements que estan entre [ ] són d'ús opcional i es descriuran més endavant. El bloc d'instruccions que es trobi entre { i } s'executarà de forma repetitiva mentre el resultat de condicio sigui true.

La condició pot estar formada per una variable booleana (que sol pot contenir dos valors true o false) o bé per una operació lògica o de comparació que retorna com a resultat un valor booleà.

L'exemple següent ens mostra el funcionament d'aquesta estructura de control. L'objectiu és calcular la mitjana d'un conjunt de números. Aquests números s'introduiran per part de l'usuari mitjançant un quadre de diàleg. Inicialment es desconeix el nombre de valors que s'introduiran.

La introducció dels números finalitzarà quan l'usuari premi sobre el botó "Cancelar" del quadre de diàleg, per tant, inicialment no sabem quina quantitat de números s'introduiran.

<script language="JavaScript">
  <!--
  var acumulat=0;
  var nValors=0;
  var valor=prompt("Introdueix un no. (CANCELAR per acabar)","");
  while (valor != null)
  {
    acumulat += parseInt(valor);
    ++nValors;
    valor=prompt("Introdueix un no. (CANCELAR per acabar)","");
  }
  alert("La mitjana val: " + eval(acumulat/nValors));
  // -->
</script>

 
En el funcionament d'aquest codi, es declaren i s'inicialitzen les variables acumulat, nValors i valor. Les dues primeres, seran de tipus numèric, ja que s'han inicialitzat amb zero, ara bé, la variable valor s'inicialitza a un format de cadena de text, ja que la funció prompt retorna una cadena de text.

La variable acumulat contindrà la suma acumulada dels valors numèrics i nValors la quantitat de valors introduïts per l'usuari.

La línia while (valor != null) és l'inici del bloc while i el contingut del parèntesi la condició que ha de ser certa perquè es repeteixi el contingut interior del bucle. S'ha de tenir en compte que el quadre de diàleg prompt retorna el valor null quan es prem a sobre del botó Cancelar. Aquesta condició compara el contingut de la variable de cadena valor amb null. Si són diferents retornarà el valor booleà true, en cas contrari retornarà false.

A l'interior del bloc while, tenim les següents línies de codi:

    acumulat += parseInt(valor);
Aquesta línia afegeix a la variable acumulat el valor numèric de la variable valor, l'operador d'assignació += equival a: acumulat = acumulat + parseInt(valor);. La funció parseInt() converteix la cadena de text que conté valor a un valor numèric, per poder-ho sumar a la variable acumulat.

    ++nValors;
Aquesta línia incrementa en una unitat a la variable nValors, l'operador aritmètic ++ equival a la següent operació: nValors = nValors + 1.

    valor=prompt("Introdueix un no. (CANCELAR per acabar)","");
Aquesta última línia del bucle és igual a la que existeix just abans d'iniciar el bucle while. La seva funció és sol·licitar un nou valor a l'usuari i assignar-lo a la variable valor. L'existència d'aquesta línia és molt important ja que introdueix la variació sobre la variable que s'avalua en la condició de while, si la variable valor no canvies mai, no seria possible acabar el bucle while i, generalment, produiria un error.

En el moment que l'usuari prem el botó Cancelar, la condició del bucle while passa a ser false i finalitza el bucle de repetició. S'ha de remarcar que hi ha la possibilitat que el contingut del bucle while no s'arribi a executar ni una sola vegada, això es pot aconseguir si en l'execució del primer prompt, que està just abans de l'inici del while, es prem directament sobre Cancelar.

Finalment, quan s'ha sortit del bucle, s'executa la línia:

    alert("La mitjana val: " + eval(acumulat/nValors));
Aquesta línia mostra un missatge amb el text "La mitjana val: " concatenat amb el resultat d'avaluar l'operació algebraica: acumulat / nValors que ens dóna la mitjana aritmètica del conjunt numèric introduït per l'usuari.

 
2.- Evitem els errors.
El programa de l'apartat 1 és molt vulnerable. Suposem que l'usuari introdueix un valor que no és numèric o en blanc, en aquest cas, es continuarà de forma normal, però, a l'hora de mostrar el resultat veurem que no és correcte (mostrarà NaN, Not a Number).

També hi cap la possibilitat que l'usuari premi Cancelar just en la primera consulta, en aquest cas ja s'ha dit que el bloc del bucle no s'arribarà a executar mai, això provoca que la variable nValors contingui el valor 0 i a la línia de l' alert es farà una divisió per zero ja que aquesta variable està situada en el denominador. S'ha d'evitar que en aquesta situació es faci la divisió per zero.

Les instruccions break i continue es poden introduir dins l'estructura while (també dins el for i el do...while) i provoquen un comportament diferent d'aquesta estructura. Habitualment se solen executar en funció d'una determinada situació que es detecta mitjançant una estructura condicional if.

La instrucció break situada dins un bucle, provoca la interrupció de l'execució de les instruccions del bloc i finalitza el bucle, independentment del resultat de la condició del bucle.

La instrucció continue, en canvi, provoca que es torni a iniciar l'execució de les instruccions del bucle sense acabar la seqüència actual.

L'exemple següent resol els inconvenients indicats prèviament. És a dir, quan s'introdueixi un valor que no pugui ser convertit en numero enter o sigui un camp buit, s'executarà un break que provocarà la finalització del bucle independentment del valor de la condició del bucle. per fer-ho es fa anar la línia:

      if(isNaN(valor) || valor=="") break;

if és un condicional que s'estudia amb més detall en la pràctica següent. Dins el parèntesi tenim una condició que avalua si el contingut de la variable valor és numèrica mitjançant el mètode isNaN(), que verifica si el contingut de valor pot ser convertit en número. També s'avalua si el contingut de valor és un valor buit (valor==""). Si es compleix una condició o l'altra se surt del bucle amb el break. El símbol || indica l'operació lògica o.

Si desitgéssim menysprear el valor no numèric i tornar a demanar un nou valor sense sortir del bucle, podríem utilitzar la sentència continue per tornar a iniciar el bucle, però abans, hauríem de tornar a demanar un nou valor numèric a l'usuari, advertint-lo del seu error. La línia que conté el break la podríem substituir per les següents:

      if (isNaN(valor) || valor=="") {
          valor=prompt("No. erroni, introdueix un nou valor numèric (FI per acabar)","");
          continue;
      }


En el cas d'utilitzar l'opció amb la sentència continue, si s'introdueix un valor no numèric es tornarà a demanar a l'usuari el nou valor fins que aquest sigui correcte o bé, premi sobre Cancelar.
per evitar l'error de la divisió per zero verificarem si nValor no val zero, si és cert no s'executarà la instrucció alert, les següents línies de codi serveixen per aquesta verificació:

      if (nValors != 0) alert("La mitjana val: " + eval(acumulat/nValors));
      else alert("Ep! No has introduït cap valor");


El codi complet és el que s'indica a continuació, s'hi ha utilitzat l'opció de break en el cas que s'hagi introduït un valor no numèric. Podeu fer la prova de substituir la línia del break per les línies de codi indicades prèviament amb l'opció de continue i comprovar el seu funcionament diferenciat.

<script language="JavaScript">
  <!--
  var acumulat=0;
  var nValors=0;
  var valor=prompt("Introdueix un no. (CANCELAR per acabar)","");
  while (valor != null)
  {
    if(isNaN(valor) || valor=="") break;
    acumulat += parseInt(valor);
    ++nValors;
    valor=prompt("Introdueix un no. (CANCELAR per acabar)","");
  }
  if (nValors != 0) alert("La mitjana val: " + eval(acumulat/nValors));
  else alert("Ep! No has introduït cap valor");
  // -->
</script>

 
3.- Llista de nombres parells. Bucles do ... while().
L'estructura iterativa do ... while és molt semblant al comportament de while. L'única diferència és que en aquest cas, la condició s'avalua al final del bloc, per tant, a diferència del while, el bloc de codi a repetir s'executarà sempre, com a mínim una vegada.

La sintaxi genèrica d'aquesta estructura és:

      do {
        ..instruccions..
        [break]
        ..instruccions..
        [continue]
        ..instruccions..
      }
while(condicio)

Aquesta estructura de control s'ha de llegir de la següent forma:
            fer ... mentre la condició sigui certa.

El següent exemple escriu sobre el document els nombres parells entre 0 i el màxim indicat per l'usuari. Per fer-ho s'utilitza la sentència do ... while. Observeu com, encara que es premi Cancelar o Aceptar amb un valor zero o buit o no numèric, sempre apareix com a mínim el primer valor 0.

<script language="JavaScript">
  <!--
  var fi=prompt("Introdueix el valor màxim:","");
  var valor=0;
  do {
      document.writeln(valor + " ");
      valor = valor + 2;
  } while (valor < fi)
  // -->
</script>

 
4.- Els números primers.
L'exemple que tenim a continuació mostra una altra aplicació amb l'estructura de control while. Aquest és una mica més complex, ja que el bloc contingut dins el while és més extens i conté altres estructures de control.

L'objectiu d'aquest codi consisteix en escriure sobre la finestra un nombre determinat de nombres primers començant pel 1.

Inicialment ens sol·licita la introducció del màxim nombre primer a representar mitjançant una finestra de diàleg emergent, aquest valor el desa a la variable fi.

Posteriorment s'inicia el bucle while que s'executarà de forma iterativa mentre la variable numero tingui un valor inferior al valor contingut per la variable fi. Al final del bucle while tenim la línia amb el codi ++numero; encarregada d'incrementar el valor de numero i a la vegada, modificar el valor de la condició.

També dins el bucle while hi tenim una altra estructura iterativa, en aquest cas és la for. Aquest bucle for s'encarrega de determinar si numero és un valor primer o no. Per fer-ho, s'utilitza la variable primer com a booleana i se li assigna inicialment el valor true.

Dins el bucle for, s'efectua múltiples divisions entre el numero i qualsevol altre número entre 2 i numero/2. A cada divisió es verifica si el residu (%) és igual a 0, en cas de ser-ho, vol dir que el numero no és primer i es posa la variable primer a false i sortim del bucle for mitjançant el break.

Seguidament, si primer val true, vol dir que el numero és primer i s'escriu sobre la finestra activa el valor de numero.

El bucle while es repetirà tants cops com sigui necessari fins arribar al número màxim indicat per l'usuari, desat dins la variable fi.

<script languaje="JavaScript">
//numeros primers.

  var fi=prompt("Introdueix el màxim nombre primer a visualitzar:","");
  var a, primer, numero=1;
  while(numero <= fi) {
      primer = true;
      for(a=2; a<=numero/2; a++) {
          if ((numero % a) == 0) {
              primer = false;
              break;
          }
      }
      if (primer) document.write(numero + " ");
      ++numero;
  }
</script>