Los 10 errores de JavaScript más importantes de más de 1000 proyectos (y cómo evitarlos)

Para retribuir a nuestra comunidad de desarrolladores, miramos nuestra base de datos de miles de proyectos y encontramos los 10 errores principales en JavaScript. Le mostraremos qué los causa y cómo evitar que sucedan. Si evita estos “errores”, lo convertirá en un mejor desarrollador.

Debido a que los datos son el rey, recopilamos, analizamos y clasificamos los 10  errores de JavaScript principales . Rollbar recopila todos los errores para cada proyecto y resume cuántas veces ocurrió cada uno. Hacemos esto agrupando los errores según sus huellas dactilares . Básicamente, agrupamos dos errores si el segundo es solo una repetición del primero. Esto les da a los usuarios una visión general agradable en lugar de un gran vertedero abrumador como lo vería en un archivo de registro.

Nos centramos en los errores que con mayor probabilidad le afectarán a usted y a sus usuarios. Para hacer esto, clasificamos los errores por el número de proyectos que los experimentan en diferentes compañías. Si observamos solo el número total de veces que se produjo cada error, los clientes de alto volumen podrían abrumar al conjunto de datos con errores que no son relevantes para la mayoría de los lectores.

Aquí están los primeros 10 errores de JavaScript :

Cada error se ha acortado para facilitar la lectura. Profundicemos en cada uno para determinar qué puede causarlo y cómo puede evitar crearlo.

1. TypeError no capturado: no se puede leer la propiedad

Si es un desarrollador de JavaScript, probablemente haya visto este error más de lo que le gustaría admitir. Esto ocurre en Chrome cuando lee una propiedad o llama a un método en un objeto indefinido. Puedes probar esto muy fácilmente en Chrome Developer Console.

Esto puede ocurrir por muchos motivos, pero uno común es la inicialización incorrecta del estado al representar los componentes de la interfaz de usuario. Veamos un ejemplo de cómo puede ocurrir esto en una aplicación del mundo real. Seleccionaremos Reaccionar, pero los mismos principios de inicialización incorrecta también se aplican a Angular, Vue o cualquier otro marco.

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 se dan cuenta aquí:

  1. El estado de un componente (por ejemplo this.state) comienza su vida como undefined.
  2. Cuando recupera datos de forma asincrónica, el componente se procesará al menos una vez antes de que se carguen los datos, independientemente de si se han obtenido en el constructor componentWillMountcomponentDidMount. Cuando Quiz primero se representa, this.state.itemsno está definido. Esto, a su vez, significa que los ItemListelementos no están definidos y se obtiene un error: “UnEdge TypeError: no se puede leer la propiedad ‘map’ undefined” en la consola.

Esto es fácil de arreglar. La forma más sencilla: Inicializar el estado con valores predeterminados 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>
    );
  }
}

El código exacto en su aplicación puede ser diferente, pero esperamos haberle dado suficiente pista para corregirlo o evitar este problema en su aplicación. De lo contrario, continúe leyendo porque a continuación, cubriremos más ejemplos de errores relacionados.

2. TypeError: ‘undefined’ no es un objeto (evaluando

Este es un error que ocurre en Safari cuando lee una propiedad o llama a un método en un objeto indefinido. Puede probar esto muy fácilmente en la consola de desarrollo de Safari. Esto es esencialmente el mismo que el error anterior para Chrome, pero Safari usa un mensaje de error diferente.

3. TypeError: null no es un objeto (evaluando

Este es un error que ocurre en Safari cuando lee una propiedad o llama a un método en un objeto nulo. Puede probar esto muy fácilmente en la consola de desarrollo de Safari.

Curiosamente, en JavaScript, nulo e indefinido no son lo mismo, por lo que vemos dos mensajes de error diferentes. Indefinido suele ser una variable que no se ha asignado, mientras que nulo significa que el valor está en blanco.Para verificar que no son iguales, intente utilizar el operador de igualdad estricta:

Una forma en que este error puede ocurrir en un ejemplo del mundo real es si intenta usar un elemento DOM en su JavaScript antes de que se cargue el elemento. Esto se debe a que la API DOM devuelve nulo para referencias de objetos que están en blanco.

Cualquier código JS que ejecute y trate con elementos DOM debería ejecutarse después de que se hayan creado los elementos DOM. El código JS se interpreta de arriba a abajo como se establece en el HTML. Entonces, si hay una etiqueta antes de los elementos DOM, el código JS dentro de la etiqueta script se ejecutará cuando el navegador analice la página HTML. Obtendrá este error si los elementos DOM no se han creado antes de cargar el script.

En este ejemplo, podemos resolver el problema agregando un detector de eventos que nos notificará cuando la página esté lista. Una vez que addEventListenerse dispara, el init()método puede hacer uso de los elementos 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. (desconocido): Error de secuencia de comandos

El error de secuencia de comandos se produce cuando un error de JavaScript no capturado cruza los límites del dominio en violación de la política de origen cruzado. Por ejemplo, si aloja su código JavaScript en un CDN, cualquier error no detectado (errores que surgen en el controlador window.onerror, en lugar de quedar atrapado en try-catch) se informará como simplemente “Error de script” en lugar de contener útiles información. 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 reales, haga lo siguiente:

1. Enviar el encabezado Access-Control-Allow-Origin
Establecer el Access-Control-Allow-Originencabezado en * significa que se puede acceder al recurso correctamente desde cualquier dominio. Puede reemplazar * con su dominio si es necesario: por ejemplo Access-Control-Allow-Origin: www.example.com,. Sin embargo, manejar dominios múltiples es complicado, y puede que no valga la pena si usa un CDN debido a problemas de almacenamiento en caché que puedan surgir. Ver más aquí .

Aquí hay algunos ejemplos sobre cómo configurar este encabezado en varios entornos:

Apache
En las carpetas donde se servirán sus archivos JavaScript, cree un .htaccessarchivo con los siguientes contenidos:

Header add Access-Control-Allow-Origin "*"

Nginx
Agregue la directiva add_header al bloque de ubicación que sirve sus archivos JavaScript:

location ~ ^/assets/ {
    add_header Access-Control-Allow-Origin *;
}

HAProxy
Agregue lo siguiente a su back-end de activos donde se sirven los archivos de JavaScript desde:

rspadd Access-Control-Allow-Origin:\ *

2. Establezca crossorigin = “anonymous” en la etiqueta del script
En su fuente HTML, para cada uno de los scripts para los que ha establecido el Access-Control-Allow-Originencabezado, crossorigin="anonymous"configúrelo en la etiqueta SCRIPT. Asegúrese de verificar que el encabezado se está enviando para el archivo de script antes de agregar la crossoriginpropiedad en la etiqueta del script. En Firefox, si el crossoriginatributo está presente pero el Access-Control-Allow-Originencabezado no, el script no se ejecutará.

5. TypeError: Object no admite propiedad
Este es un error que ocurre en IE cuando llama a un método indefinido. Puede probar esto en la Consola de desarrollador de IE.

Esto es equivalente al error “TypeError: ‘undefined’ no es una función” en Chrome. Sí, diferentes navegadores pueden tener diferentes mensajes de error por el mismo error lógico.

Este es un problema común para IE en aplicaciones web que emplean el espacio de nombres JavaScript. Cuando este es el caso, el problema es 99.9% del tiempo es la incapacidad de IE para vincular los métodos dentro del espacio de nombres actual a la thispalabra clave. Por ejemplo, si tiene el espacio de nombres JS Rollbarcon el método isAwesome.Normalmente, si se encuentra dentro del Rollbarespacio de nombres, puede invocar el isAwesomemétodo con la siguiente sintaxis:

this.isAwesome();

Chrome, Firefox y Opera aceptarán esta sintaxis. IE, por otro lado, no lo hará. Por lo tanto, la apuesta más segura al utilizar el espacio de nombres JS es siempre el prefijo con el espacio de nombres real.

Rollbar.isAwesome();

6. TypeError: ‘undefined’ no es una función

Este es un error que ocurre en Chrome cuando llama a una función no definida. Puedes probar esto en Chrome Developer Console y Mozilla Firefox Developer Console.

Como las técnicas de codificación y los patrones de diseño de JavaScript se han vuelto cada vez más sofisticados a lo largo de los años, ha habido un aumento correspondiente en la proliferación de ámbitos de autorreferencia dentro de las devoluciones de llamadas y cierres, que son una fuente bastante común de esta / esa confusión.

Considere este ejemplo de fragmento de código:

function clearBoard(){
  alert("Cleared");
}
document.addEventListener("click", function(){
  this.clearBoard(); // what is “this” ?
});

 

Si ejecuta el código anterior y luego hace clic en la página, se produce el siguiente error “TypeError no capturado: this.clearBoard no es una función”. La razón es que la función anónima que se está ejecutando está en el contexto del documento, mientras que clearBoardestá definida en la ventana.

Una solución tradicional, compatible con el viejo navegador es simplemente guardar su referencia thisen una variable que luego puede ser heredada por el cierre. Por ejemplo:

 

var self=this;  // save reference to 'this', while it's still this!
document.addEventListener("click", function(){
  self.clearBoard();
});

Alternativamente, en los navegadores más nuevos, puede usar el bind()método para pasar la referencia adecuada:

document.addEventListener("click",this.clearBoard.bind(this));

 

7. RangeError no capturado: pila de llamadas máxima

Este es un error que ocurre en Chrome en algunas circunstancias. Una es cuando llamas a una función recursiva que no termina. Puedes probar esto en Chrome Developer Console.

También puede suceder si pasa un valor a una función que está fuera de rango. Muchas funciones aceptan solo un rango específico de números para sus valores de entrada. Por ejemplo, Number.toExponential(digits)umber.toFixed(digits)acepta dígitos del 0 al 20 y Number.toPrecision(digits)acepta dígitos 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: no se puede leer la propiedad ‘length’

Este es un error que ocurre en Chrome debido a la lectura de la propiedad de longitud para una variable indefinida. Puedes probar esto en Chrome Developer Console.

Normalmente se encuentra la longitud definida en una matriz, pero es posible que se encuentre con este error si la matriz no se inicializa o si el nombre de la variable está oculto en otro contexto. Comprendamos este error con el siguiente 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 se vuelven locales. Esto significa que incluso si tiene variables con nombres testArray, los parámetros con los mismos nombres dentro de una función se tratarán como locales.

Tienes dos formas de resolver tu problema:

  1. Elimine los parámetros en la declaración de declaración de función (resulta que desea acceder a las variables que están declaradas fuera de la función, por lo que no necesita parámetros para su función):

 

var testArray = ["Test"];

/* Precondition: defined testArray outside of a function */
function testFunction(/* No params */) {
   for (var i = 0; i < testArray.length; i++) {
     console.log(testArray[i]);
   }
}

testFunction();

2. Invoque la función pasando la matriz que declaramos:

var testArray = ["Test"];

function testFunction(testArray) {
  for (var i = 0; i < testArray.length; i++) {
     console.log(testArray[i]);
   }
}

testFunction(testArray);

9. TypeError no detectado: no se puede establecer la propiedad

Cuando intentamos acceder a una variable indefinida, siempre regresa undefinedy no podemos obtener ni establecer ninguna propiedad de undefined. En ese caso, una aplicación arrojará “Unkeught TypeError no puede establecer la propiedad de indefinido”.

Por ejemplo, en el navegador Chrome:

Si el testobjeto no existe, el error arrojará “Unkeught TypeError no puede establecer la propiedad de indefinido”.

10. ReferenceError: evento no definido

Este error se produce cuando intenta acceder a una variable que no está definida o está fuera del alcance actual. Puedes probarlo muy fácilmente en el navegador Chrome.

Si obtiene este error cuando usa el sistema de manejo de eventos, asegúrese de usar el objeto de evento pasado como parámetro. Navegadores más antiguos como IE ofrecen un evento variable global, y Chrome adjunta automáticamente la variable de evento al controlador. Firefox no lo agregará automáticamente. Las bibliotecas como jQuery intentan normalizar este comportamiento. Sin embargo, es una buena práctica usar el que pasó a su función de controlador de eventos.

document.addEventListener("mousemove", function (event) {
  console.log(event);
})

 

Conclusión

Resulta que muchos de estos son errores nulos o indefinidos. Un buen sistema de comprobación de tipo estático como Typescript podría ayudarlo a evitarlos si utiliza la opción de compilación estricta. Puede avisarte si se espera un tipo pero no se ha definido. Incluso sin Typescript, es útil usar cláusulas de protección para verificar si los objetos no están definidos antes de usarlos.

Esperamos que haya aprendido algo nuevo y pueda evitar errores en el futuro, o que esta guía lo haya ayudado a resolver un rascador de cabeza. Sin embargo, incluso con las mejores prácticas, aparecen errores inesperados en la producción. Es importante tener visibilidad de los errores que afectan a los usuarios y tener buenas herramientas para resolverlos rápidamente.

Rollbar le ofrece visibilidad de los errores de JavaScript de producción y le brinda más contexto para resolverlos rápidamente. Por ejemplo, ofrece funciones adicionales de depuración como la telemetría que le informa qué sucedió en el navegador del usuario hasta el error. Es una idea que no tienes fuera de tu consola de desarrollador local. Obtenga más información en la lista completa de características de Rollbar para aplicaciones de JavaScript .

Si aún no lo hizo, regístrese para una versión de prueba gratuita de 14 días de Rollbar y permítanos ayudarle a tomar el control de los errores de JavaScript impactantes. 🙂

Este artículo se publicó originalmente en Rollbar.com y se ha vuelto a publicar con permiso.
Si esta publicación fue útil, haga clic en el botón aplacar abajo algunas veces para mostrar su apoyo. ⬇⬇
JavaScriptDesarrollo webTecnologíaCodificaciónProgramación

Leave a Reply

Your email address will not be published. Required fields are marked *

Ir a la barra de herramientas