10 errores que los novatos de Javascript suelen cometer - Parte 2

Javascript es un lenguaje sencillo con el cual comenzar a aprender programación, pero lograr ser un experto en la materia requiere mucho esfuerzo. Los novatos, a menudo, cometen errores que ya son conocidos por los desarrolladores experimentados en Javascript, y siguen cayendo, y cayendo, y cayendo, hasta que un día, por fin, se les mete en la sesera. Si quieres saber de qué errores estamos hablando, sigue leyendo este artículo:

Usar constructores sobre literales

Cuando los programadores de Java y C# codifican en Javascript, a menudo prefieren crear objetos utilizando constructores: new Array(), new Object(), new String(). A pesar de que estas declaraciones son perfectamente compatibles con el lenguaje, se recomienda utilizar anotaciones literalea: [], {}, "", debido a que las funciones constructoras cuentas con sutiles peculiaridades:

/* Using array constructors is valid, but not recommended. Here is why. */

// Create an array with four elements:

var elem4 = new Array(1,2,3,4);

console.log('Four element array: ' + elem4.length);

// Create an array with one element. It doesn't do what you think it does:

var elem1 = new Array(23);

console.log('One element array? ' + elem1.length);

/* String objects also have their warts */

var str1 = new String('JavaScript'),
	str2 = "JavaScript";

// Strict equality breaks:

console.log("Is str1 the same as str2?", str1 === str2);

La solución es simple: intenta utilizar siempre notaciones literales. Además, la longitud de los arrays de Javascript no debe ser establecida con antelación.

No entender cómo funciona el ámbito de las variables

Un concepto difícil para los principiantes de Javascript es entender el ámbito de reglas y cierres. Y con razón:

// Print the numbers from 1 to 10, 100ms apart. Or not.

for(var i = 0; i < 10; i++){
	setTimeout(function(){
		console.log(i+1);
	}, 100*i);
}

/* To fix the bug, wrap the code in a self-executing function expression:

for(var i = 0; i < 10; i++){

	(function(i){
		setTimeout(function(){
			console.log(i+1);
		}, 100*i);
	})(i);

}				

*/

Las funciones conservan la visibilidad de sus variables en el ámbito de sus padres. Pero debido a que estamos retrasando la ejecución con un setTimeout, cuando llegue el momento de que las funciones se ejecuten, el bucle ya habrá terminado y la variable i se incrementará a 11.

Utilizando eval

Eval is evil, dicen los programadores ingleses. El uso de eval se considera una mala práctica, y en la mayoría de las veces en que lo utilizas, fijo que hay una solucióm mejor y más rápida.

/* Using eval to access properties dynamically */

var obj = {
	name: 'Foo Barski',
	age: 30,
	profession: 'Programmer'
};

// Which property to access?
var access = 'profession';

// This is a bad practice. Please don't do it:
console.log( eval('obj.name + " is a " + obj.' + access) );

// Instead, use array notation to access properties dynamically:
console.log( obj.name + " is a " + obj[access]);

/* Using eval in setTimout */

// Also bad practice. It is slow and difficult to read and debug:
setTimeout(' if(obj.age == 30) console.log("This is eval-ed code, " + obj[access] + "!");', 100);

// This is better:
setTimeout(function(){

	if(obj.age == 30){
		console.log('This code is not eval-ed, ' + obj[access] + '!');
	}

}, 100);

El código dentro de eval es una cadena. Los mensajes de debug que surgen a partir de bloques eval son incomprensibles y casi siempre tienes que escaparlos con comillas simples y dobles. Por no hablar de que esto hace que la ejecución de Javascript se ralentice. No utilices eval a menos que sepas lo que estás haciendo.

No entender el código asíncrono

Algo que es único en JavaScript es que casi todo es asíncrono, y necesitas pasar callback functions con el fin de ser notificado de lo que ha ocurrido. Esto no es muy intuitivo para los novatos, y rápidamente los puedes ver rascándose la cabeza con un error que, para ellos, es difícil de entender. He aquí un ejemplo, en el que uso el servicio FreeGeoIP para buscar tu ubicación a través de la IP:

var userData = {};

// Fetch the location data for the current user.
load();

// Output the location of the user. Oops, it doesn't work! Why?
console.log('Hello! Your IP address is ' + userData.ip + ' and your country is ' + userData.country_name);

// The load function will detect the current visitor's ip and location with ajax, using the
// freegeoip service. It will place the returned data in the userData variable when it's ready.

function load(){

	$.getJSON('http://freegeoip.net/json/?callback=?', function(response){
		userData = response;

		// Uncomment this line to see what is returned:
		// console.log(response);
	});
}

A pesar de que console.log() esté después de la función load(), en realidad se ejecutará antes de que los datos se lean.

Mal uso de los listeners de eventos

Digamos que quieres recibir los clics de un botón, pero sólo cuando un checkbox esté marcado. Así es como un novato lo haría (con jQuery):

<input type="checkbox" />

<button>Click me!</button>

<p>Click the checkbox a few times.</p>
var checkbox = $('input[type=checkbox]'),
	button = $('button');

// We want to listen for clicks only when the checkbox is marked.

checkbox.on('change', function(){

	// Is the checkbox checked?

	if(this.checked){

		// Listen for clicks on the button. 

		button.on('click', function(){

			// This alert is called more than once. Why?

			alert('Hello!');
		});
	}
});

Esto está mal, obviamente. Idealmente, debes recibir un evento una sola vez, al igual que hemos hecho con el evento change del checkbox. Llamar repetidamente al button.on("click"...) deriva en múltiples listeners de eventos que no se podrán eliminar.

COMPARTE ESTE ARTÍCULO

COMPARTIR EN FACEBOOK
COMPARTIR EN TWITTER
COMPARTIR EN LINKEDIN
COMPARTIR EN WHATSAPP