Lenguajes de Programación
Los 10 errores más comunes en JavaScript y cómo evitarlos
Conoce los errores más comunes en JavaScript según un estudio basado en el análisis de más de 1000 proyectos JavaScript, y cómo como evitarlos para ser más productivo.
En este artículo te mostramos el Top de 10 errores principales en JavaScript, qué los causa y como evitarlos. Si logras evitar estos errores, te convertirás en un desarrollador más eficaz.
Aqui nos centraremos en los 10 errores que con mayor probabilidad suelen aparecer. Este estudio es de RollBar, y está hecho sobre una muestra de más de 1000 proyectos JavaScript.
Los 10 errores más comunes en JavaScript
Aquí tienes la gráfica de los errores más comunes que han aparecido en el muestreo de más de 1000 proyectos. Analizaremos cada uno de estos errores para evitarlos en nuestros futuros proyectos.
1 - Uncaught TypeError : cannot read property
Si eres un desarrollador JavaScript, lo más probable es que hayas visto este error más de lo que quisieras admitir. Este error ocurre en Chrome cuando lee una propiedad o llama a un método de un objeto indefinido.
Puedes probar esto muy fácilmente con la consola de Chrome:
Esto puede ocurrir por varias razones, pero lo común es por culpa de la inicialización incorrecta del estado al representar los componentes de la interfaz de usuario.
Veamos un ejemplo en React, pero los mismos principios de inicialización incorrecta también aplican para Angular, Vue o cualquier otro framework:
class Quiz extends Component {
componentWillMount() {
axios.get('/thedata').then(res => {
this.setState({items: res.data});
});
}
render() {
return (
<ul>
{this.state.items.map(item =>
<li key={item.id}>{item.name}</li>
)}
</ul>
);
}
}
`
Hay dos cosas importantes que pasan aquí:
- El estado de un componente (ejemplo: this.state) comienza como indefinido.
- Cuando recuperas los datos de manera asíncrona, el componente se renderizará al menos una vez antes de que se carguen los datos, independiente de si se han obtenido en el constructor,
componentWillMount
ocomponentDidMount
. Cuando enQuiz
renderiza por primera vez,this.state.items
es indefinido (undefined). Esto, a su vez, significa queItemList
obtiene los elementos como indefinidos y se obtiene el error: “Uncaught TypeError: cannot read property ‘map’ of undefined” en la consola.
Este error es fácil de arreglar de la siguiente manera: Inicializa el estado con valores por defecto razonables en el constructor.
class Quiz extends Component {
// Added this:
constructor(props) {
super(props);
// Assign state itself, and a default value for items
this.state = {
items: []
};
}
componentWillMount() {
axios.get('/thedata').then(res => {
this.setState({items: res.data});
});
}
render() {
return (
<ul>
{this.state.items.map(item =>
<li key={item.id}>{item.name}</li>
)}
</ul>
);
}
}
NOTA
El código exacto en tu aplicación puede ser diferente, pero esperamos que este ejemplo sirva para que puedas corregir este tipo de error y evitarlo en tu app.
2 - TypeError: ‘undefined’ is not an object (evaluating)
Este es un error que ocurre en Safari cuando lees una propiedad o llamas a un método en un objeto indefinido. Puedes probar esto fácilmente en la consola de Safari. Este es prácticamente el mismo error que el anterior para Chrome, pero para Safari usa un mensaje de error diferente.
Habría que tomar las mismas soluciones.
3 - TypeError: null is not an object (evaluating)
Este es un error que aparece en Safari cuando lees una propiedad o llama a un método de un objeto nulo. Puedes probar esto en la consola de Safari.
Recuerda que en JavaScript, null o undefined no son lo mismo, por lo que se ven dos mensajes de error diferentes.
Undefined
suele ser una variable que se ha asignado, mientras que Null
significa que el valor esta en blanco. Para verificar que no son iguales, hay que usar el operador de igualdad estricta para verificarlo:
-
Este error puede aparecer si se intenta usar un elemento DOM en JavaScript antes de que se cargue el elemento. Esto se debe a que la API DOM devuelve null.
-
Cualquier código JavaScript con elementos en el DOM debería ejecutarse después de que se hayan creado los elementos en el DOM.
En JavaScript el código se interpreta de arriba a abajo como se describe en el HTML. Entonces si hay una etiqueta antes de que cargue los elementos del DOM, por tanto arrojaria dicho error si el orden no es el correcto.
En este ejemplo, podemos resolver este problema añadiendo un evento listener que nos notificará cuando la pagina esté lista. Una vez que ddEventListener
se activa, el método init()
puede hacer uso de los elementos del DOM.
<script>
function init() {
var myButton = document.getElementById("myButton");
var myTextfield = document.getElementById("myTextfield");
myButton.onclick = function() {
var userName = myTextfield.value;
}
}
document.addEventListener('readystatechange', function() {
if (document.readyState === "complete") {
init();
}
});
</script>
<form>
<input type="text" id="myTextfield" placeholder="Type your name" />
<input type="button" id="myButton" value="Go" />
</form>
4 - Unknown: Script error
Este error nos avisa cuando se origina un error de un archivo JavaScript servido desde un origen diferente (dominio, puerto o protocolo diferente).
Es un error que no sabemos de donde viene ya que, no se sabe cuál es el error, ni de parte del código se está originando este error.
Por ejemplo, si nuestro código está en un CDN, cualquier error no capturado se informará simplemente como Script error, en lugar de contener información útil.
Esta es una medida de seguridad del navegador destinada a evitar el paso de datos a través de dominios que de otro modo no podrían comunicarse.
Para obtener los mensajes de error con información útil, debes hacer lo siguiente:
-
Añadir una cabecera Cross Origin Resource Sharing (CORS), configurando la cabecera
access-control-allow-origin
en tú codigo(*
) significa que se puede acceder al recurso correctamente desde cualquier dominio. Puedes reemplazar el*
con tu dominio de acceso, por ejemplo:Ejemplo: access-control-allow-origin: www.ejemplo.com.
Sin embargo, manejar diferentes dominios es complicado y puede que no valga la pena si usas un CDN debido a problemas de almacenamiento en caché que puedan surgir. Puedes ver más información sobre este tema en el hilo de Stack Overflow aquí
Vamos a ver algunos ejemplos sobre como configurar este encabezado en varios entornos:
Apache:
Crear o modifica tu archivo.htaccess
con la siguiente expresión:Header add Access-Control-Allow-Origin "*"
Nginx:
Añadir la directivaadd_header
:location ~ ^/assets/ { add_header Access-Control-Allow-Origin *; }
HAProxy:
Agregua la dirfectiva siguiente a tu backend:rspadd Access-Control-Allow-Origin:\ *
-
Agregar un encabezado HTTP Cross Origin en tu fuente HTML, para cada uno de los scripts para los que se ha establecido el encabezado
access-control-allow-origin
, debes establecercrossorigin="anonymous"
en la etiqueta script.Asegurate de verificar el envío antes de agregar el encabezado
crossorigin="anonymous"
. En Firefox, si el atributo está presente pero el encabezado no lo está, el script NO se ejecutara.
5 - TypeError: Object doesn’t support property
Este es un error que ocurre en Internet Explorer cuando haces uso de un método indefinido. Puedes consultarlo en la consola de IE:
Este es un equivalente al error “TypeError: ‘undefined’ no es una función” en Chrome. Si, diferentes navegadores pueden tener diferentes mensajes por el mismo error.
Este es un problema común para Internet Explorer en aplicaciones web que emplean namespace. Cuando este es el caso, el 99.9% del tiempo es la incapacidad de IE de vincular métodos dentro del namespace actual con la palabra clave this
.
Por ejemplo: Si tienes un namespace llamado Rollbar con el método isAwesome(),si este se encuentra dentro de namespace Rollbar puedes invocar dicho método con la siguiente sintaxis:
this.isAwesome();
Chrome, Firefox y Opera aceptará sin ningún problema esta sintaxis. IE, por otro lado, no lo hará. Por lo tanto, la apuesta más segura es utilizar el namespace JavaScript siempre como prefijo para llamar al metodo, asi:
Rollbar.isAwesome();
6 - TypeError: ‘undefined’ is not a function
Este es un error que ocurre en Chrome cuando llamas a una función no definida. Puedes probar esto en la consola de Chrome y Firefox:
Como las técnicas de codificación y diseño de JavaScript se han convertido más sofisticadas a lo largo de los años, ha habido un aumento correspondiente a la proliferación de ámbitos de autorreferencia dentro de las devoluciones de callbacks y closures, que son una fuente bastante común de esta confusión.
Veamos como ejemplo, el siguiente fragmento de código:
function clearBoard(){
alert("Cleared");
}
document.addEventListener("click", function(){
this.clearBoard(); // what is “this” ?
});
Si estas ejecutando el código anterior y luego haces click en la página, se produce el siguiente error: “Uncaught TypeError: this.clearBoard is not a function”.
La razón es porque la función anónima que se está ejecutando se encuentra en el contexto del documento, mientras que clearBoard
se define en el objeto Window
Para solventarlo podemos hacer una solución que se utilizaba antes en antiguos navegadores, simplemente guardar la referencia this en una variable que luego puede ser heredada..
Ejemplo:
var self=this; // save reference to 'this', while it's still this!
document.addEventListener("click", function(){
self.clearBoard();
});
Otra alternativa solo para navegadores más recientes, es que puedes usar el método bind()
para pasar la referencia adecuada:
document.addEventListener("click",this.clearBoard.bind(this));
7- Uncaught RangeError: Maximum call stack
Otro error que sólo ocurre en Chrome en dos ocasiones. Una es cuando llamamos a una función recursiva que no tiene fin.
La otra es cuando pasas un valor a una función que esta fuera del rango establecido. Muchas funciones solo aceptan un rango especifico de números para sus valores de entrada.
Por ejemplo:
**Numer.toExponential(digitos)
y Number.toFixed(digitos)
tiene un rango de dígitos del 0 al 20, y Number.toPrecision(digitos)
acepta los números del 1 al 21.
var a = new Array(4294967295); //OK
var b = new Array(-1); //range error
var num = 2.555555;
document.writeln(num.toExponential(4)); //OK
document.writeln(num.toExponential(-2)); //range error!
num = 2.9999;
document.writeln(num.toFixed(2)); //OK
document.writeln(num.toFixed(25)); //range error!
num = 2.3456;
document.writeln(num.toPrecision(1)); //OK
document.writeln(num.toPrecision(22)); //range error!
8 - TypeError: Cannot read property ‘length’
Esto es un error que ocurre en Chrome debido a la lectura de la propiedad length
para una variable indefinida. Podemos ver el fallo en la consola:
Normalmente length
está definido en un array, pero es posible que se encuentre este error si el array no se inicializa o si el nombre de la variable está oculto en otro contexto. Veamoslo con un ejemplo:
var testArray= ["Test"];
function testFunction(testArray) {
for (var i = 0; i < testArray.length; i++) {
console.log(testArray[i]);
}
}
testFunction();
Cuando declaras una función con parámetros, estos parámetros son locales. Esto significa que incluso si tienes variables con nombres testArray, los parámetros con los mismos nombres dentro de una función se trataran como locales.
Hay dos maneras de resolver este problema:
- Elimina todos los parámetros en la declaración de la función:
var testArray = ["Test"];
/* Precondición: definir testArray fuera de la función */
function testFunction(/* Sin parámetros */) {
for (var i = 0; i < testArray.length; i++) {
console.log(testArray[i]);
}
}
testFunction();
-
Llama a la función pasando el array que declaramos:
var testArray = [“Test”];
function testFunction(testArray) {
for (var i = 0; i < testArray.length; i++) { console.log(testArray[i]); } } testFunction(testArray);
9 - Uncaught TypeError: Cannot set property
Cuando tratamos de acceder a una variable no definida siempre retorna undefined y claro, no podemos obtener ni enviar ninguna propiedad de undefined. En este caso, nos dará el error **“Uncaught TypeError cannot set property of undefined.”
Replicamos el error en Chrome:
Como test tiene un valor inicial de Undefined, la consoloa nos avisará del error Uncaught TypeError cannot set property of undefined.
10 - ReferenceError: event is not defined
Y para finalizar con el top 10 de los errores más usados, vemos que este error lo encontramos cuando tratamos de acceder a una variable que no está definida o no podemos acceder a ella por que está fuera del ámbito establecido. Replicamos el error en la consola de Chrome:
Las librerias como jQuery intentan normalizar este comportamiento. Sin embargo, es una buena práctica crear este evento y usarlo:
document.addEventListener("mousemove", function (event) {
console.log(event);
})
Conclusión
Como puedes ver, la mayoria de los errores aparecen por hacer uso denulos o indefinidos. Haciendo uso de Typescript y con la compilación estricta podrías evitarlos facilmente (Fuente: Top 10 JavaScript Error from 1000+ projects).
Esperamos que con este listado de los errores más comunes en JavaScipt puedas evitarlos en un futuro y ser más eficiente. Aunque nunca evitaremos todos los errores en nuestro código, para ello es importante tener la capacidad de ver errores y resolverlos.
Comienza tu formación en JavaScript, conociendo sus fundamentos y aprendiendo a programar con la versatilidad que ofrece uno de los lenguajes de programación más usados, gracias a este curso de JavaScript para principiantes, un curso pensado para aprender de forma práctica. También es adecuado para personas que han trabajado con otras librerías como jQuery, o con frameworks como Angular, React o Vue, y quieran mejorar su base en JavaScript.