1

Estoy intentando hacer una función que efectúe unos cálculos de unas listas desplegables de la página cuando alguna de éstas cambia de valor. Sucede que la primera vez que ejecuto la función funciona correctamente pero las siguientes veces no, mostrándome el siguiente error en la consola:

Uncaught TypeError: calcularTotal is not a function

la función es la siguiente:

    <script type="text/javascript">
    function calcularTotal(){
        var total = 0;
        var rsppje = 0;
        var rsppso = 0;
        var cantPreguntas = parseInt("4");
        calcularTotal = cantPreguntas + 1;
        for (i = 1; i < calcularTotal; i++) {
            if (document.getElementById("rsppje" + i) != null) {
                rsppje = parseInt(document.getElementById("rsppje" + i).value);
                rsppso = parseInt(document.getElementById("rsppso" + i).value);
                total = total + (rsppje * rsppso) / 100;
            }
        }
        document.getElementById("puntajeTotal").innerHTML = total;
    };
</script>

El evento desde el cual llamo a la función es el siguiente (tag que se repite 4 veces en la página):

<select onchange="calcularTotal();" id="rsppje1" name="rsppje1" class="form-control">
<option selected="selected" value="0">0</option>
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
<option value="4">4</option>
<option value="5">5</option>

Y el elemento en donde luego intento mostrar el resultado de la variable, aunque en este caso creo que no tiene relevancia, es:

<span class="label label-warning" id="puntajeTotal"></span>

Desde ya muchas gracias.

Guillermo
  • 63
  • 1
  • 1
  • 13

3 Answers3

1

Es facil, lo que sucede es que esta redefiniendo la funciona, puedes hacer dos cosas,

  1. Usar "var" antes de declarar la variable:

    function calcularTotal(){
        var total = 0;
        var rsppje = 0;
        var rsppso = 0;
        var cantPreguntas = parseInt("4");
        var calcularTotal = cantPreguntas + 1;
        for (i = 1; i < calcularTotal; i++) {
            if (document.getElementById("rsppje" + i) != null) {
                rsppje = parseInt(document.getElementById("rsppje" + i).value);
                rsppso = parseInt(document.getElementById("rsppso" + i).value);
                total = total + (rsppje * rsppso) / 100;
            }
        }
        document.getElementById("puntajeTotal").innerHTML = total;
    };
    
  2. o usar un nombre diferente para la variable:

    function calcularTotal(){
        var total = 0;
        var rsppje = 0;
        var rsppso = 0;
        var cantPreguntas = parseInt("4");
        calcularTot = cantPreguntas + 1;
        for (i = 1; i < calcularTot; i++) {
            if (document.getElementById("rsppje" + i) != null) {
                rsppje = parseInt(document.getElementById("rsppje" + i).value);
                rsppso = parseInt(document.getElementById("rsppso" + i).value);
                total = total + (rsppje * rsppso) / 100;
            }
        }
        document.getElementById("puntajeTotal").innerHTML = total;
    };
    

Recuerda que cuando usas "var" haces que la variable permanezca en el ambito de la funcion.

Mariano
  • 23,777
  • 20
  • 70
  • 102
Alfredo Gt
  • 425
  • 2
  • 11
  • 1
    Gracias por tu respuesta. La verdad que no se como se me pasó ese error. – Guillermo Sep 23 '16 at 02:44
  • Un observacion @Alfredo. Definir una variable local con el mismo nombre de la funcion que lo contiene no es una buena practica, ya que en los casos que necesites hacer llamadas recursivas, una ves mas tienes el problema de perder la referencia a la funcion. Pero en esta ves, en el ambito local. – José María Sep 23 '16 at 02:55
  • asi es! @miso pero para este caso seguramente no necesita usar le función de forma recursiva. Por eso también recomende cambiar el nombre de la variable. – Alfredo Gt Sep 23 '16 at 02:59
1

El problema está en esta linea de codigo dentro de tu función:

calcularTotal = cantPreguntas + 1;

Estas volviendo a redefinir el objeto calcularTotal (la funcion). En JavaScript, las funciones tambien son objetos y mantienen una referencia, y como tal pueden volver a redefinirse.

Unos ejemplos:

// tenemos una funcion

function miFuncion() {

}

// podemos ver el tipo de objeto que es en consola
typeof(miFuncion);  // -> "function"

Eventualmente si volvemos a redefinir dicho objeto miFuncion, la referencia con la función se pierde (objeto en memoria) y se pasa a referir al nuevo objeto creado. Por ejemplo

// si asignamos un número a miFuncion
miFucion = 27;

// vemos que que miFuncion ya pasa a ser del tipo `number`
typeof(miFuncion) // -> "number"

Y si vuelves a tratar miFucion como si fuese un objeto del tipo "function", el motor JavaScript te lanzará el error:

Uncaught TypeError: calcularTotal is not a function.

José María
  • 389
  • 4
  • 9
1

Lo que sucede es que estás cometiendo el error de sobrescribir el nombre de tu función asignándole un valor diferente dentro de la función misma:

function calcularTotal() {
  .
  .
  .
  calcularTotal = cantPreguntas + 1;
};

El hecho de que declares una función con el mismo nombre al de una variable normal no quiere decir que el lenguaje las vaya a tratar de manera diferente como posiblemente sucede en lenguajes de programación fuertemente tipados. En un lenguaje tan dinámico como Javascript, todo es tratado como un objeto y las funciones no son la excepción. Te permiten hacer cosas bastante poderosas, como por ejemplo:

Realizar expresiones de función:

var miFuncion = function(arguments) { ... };
miFuncion(something);

Usar funciones como parámetro de otras (los llamados callbacks):

function a(callback) {
  callback();
}

Declarar funciones de manera anidada (closures, que por cierto es una las cosas más potentes de Javascript):

function a() {
  function b() {
    function c() {
      ...
    }
  }
}

Y muchas cosas más.

Solo debes tener en cuenta que los nombres de las funciones y variables que defines no son más que identificadores que hacen referencia a algo que se encuentra almacenado en memoria, cuyo valor puede cambiar mediante una simple asignación. Aunque es posible crear objetos cuyo valor no pueda ser cambiado, pero ya eso es otro cuento.

Mauro Aguilar
  • 721
  • 3
  • 8