lunes, 23 de marzo de 2015

Javascript: cosas a recordar

Hoy voy a anotar aquí una serie de cosas que es recomendable tener en cuenta a la hora de trabajar con Javascript. Espero que estas anotaciones me sirvan de recordatorio cada vez que tenga que trabajar con Javascript y, de paso, que puedan resultarle útiles a cualquiera que lea este blog.

- Intérprete javascript online: jsbin.com

- Usar .textContent en lugar de innerHTML por el bien de la compatibilidad con
  todos los navegadores

- Usar doc.getElementById("elemento").value en lugar de .value (este último no
  funciona en IE)
- document.getElementById("imagen").getAttribute("src");
- document.getElementById("imagen").setAttribute("src", "imagen.jpg");

- Colocar las etiquetas <script> justo antes de la etiqueta de cierre </body>. Los
  navegadores paran la  descarga del HTML al encontrar etiquetas <script> para
  descargar los ficheros .js. También se puede usar atributo
  async de <script> en navegadores modernos.

- Sensible a mayúsculas y minúsculas.

- Comentarios: // (única línea) y /* comentario */ (varias líneas)

- Tipos de datos: Number, Boolean, String. Para definir una variable usamos var.

- parseInt() y parseFloat() para convertir strings a números enteros y decimales.
  isNaN() para comprobar si es un número.
- Number(prompt("Introduce un número: ", "");  //convierte una cadena a número

- cadena1.concat(" ", cadena2);
  también se puede utilizar: cadena1 + " " + cadena2.

- cadena1 = "Hola"; cadena2 = "mundo"; cadena1.concat(" ", cadena2, "!");

- cadena1.toUpperCase(); cadena2.toLowerCase();

- "cadena de texto".length

- trim(): eliminar blancos, cadena1.replace("cadena1", "cadena2");
  El primer parámetro de replace puede   ser una expresión regular

- substring(inicio, fin); substr(inicio, contador); slice(inicio, fin);
  substr no funciona en IE8 y anteriores, slice no intercambia inicio y fin cuando   inicio>fin

- cadena1.indexOf("c"); cadena2.lastIndexOf("d");

- document.getElementById("idElemento");

- prompt("Mensaje a mostrar", "texto por defecto para devolver si el usuario no
  introduce nada");

- Definir arrays:
  var arrayVacio = []; var miArray = ["uno", "dos", "tres"];
  var array10 = new Array(10);
  var array2d = new Array(3); for (var i=0; i<3 data-blogger-escaped-array2d=""
  data-blogger-escaped-br="" data-blogger-escaped-i="" data-blogger-escaped-new="">
  Array(3);} - miArray.push("valor a añadir");
- var elemento = miArray.pop(); //devuelve el último elemento del array y lo
  elimina del mismo.
- miArray.shift(); //obtiene el primer elemento del array y lo quita del mismo
- miArray.unshift("valor"); //añade un valor como primer elemento del array.
- miArray.sort(); //por defecto supone que los elementos son strings y los ordena.
- miArray.sort(function(a,b) {return a-b}); //ordena de menor a mayor
- var a = miArray.sort(function(a,b) {return b-a}); ó a.reverse();
- miArray.splice(índice, contadorEliminar, elemento1...elementoN); //añadir y
  eliminar
- miArray.filter(esPar(value, index, array) { return value % 2; }); //sólo los
  pares
- miArray.filter(function (value, index, array) { return array.indexOf(value) ==
  index; }); //no repetidos

- Se puede usar una función antes de su definición (function hoisting).
- Funciones anónimas: var sumar = function (x, y) { return x+y }; sumar(1, 2);
- arguments.length; arguments[i]; //es un objeto no un array
  var arrayArgs = Array.prototype.slice.call(arguments); //convertir en array
- Lanzar exceptiones: throw {error: "Número inválido", message: "No es un formato
  numérico válido"}

- window.onerror = function(msg, url, line) {
  alert("Mensaje: " + msg + "\nURL: " + url + "\nLinea: " + line);
  return true; }
- <img src="imagenNoExiste.jpg" onerror="imageErrorHandler()" />
  function imageErrorHandler(msg, url, line) {alert("Hay un problema
  con la imagen");}

- var fecha = new Date(); fecha = new Date("March 26, 2015 11:06:00");
- var fecha = new Date(year, month, day, hour, minute, second, millisecond);
- fecha.getFullYear(); fecha.getMonth(); fecha.getDate(); fecha.getDay();
  fecha.getHours(); fecha.getMinutes(); fecha.getSeconds();

- var idIntervalo = window.setInterval(funcion, intervaloMilisegundos);
  window.clearInterval(idIntervalo);
- var idTemporizador = window.setTimeout(funcion, esperaMilisegundos);
  window.clearTimeout(idTemporizador);

- if (confirm("¿Está seguro?")) {return true; } else {return false;}
  onclick="return confirmOnSubmit()"

- Atributos de la propiedad style (ver aquí).
- Eventos de elementos: onclick, onblur, onmouseover, onmouseout,...
- Eventos de DOM: document.getElementById("idElemento").onmouseover =
  nombreFuncion;
- idBtn.addEventListener("mouseover", changeColorOnMouseOver, false);
- idBtn.removeEventListener("mouseover", changeColorOnMouseOver);
  (Disponibles en IE9+ y otros navegadores modernos).
- idBtn.attachEvent("onclick", clickEventHandler);
- idBtn.detachEvent("onclick", clickEventHandler);
  (Soportado en IE8 y versiones anteriores)
- if (btn.addEventListener) {... (será true para IE9+ y otros navegadores
  modernos).
- <input type="button" value="Pulsar" id="btn"
  onclick="obtenerDetallesEvento(event)" />
  function obtenerDetallesEvento(event) {   
     var sourceElement;
     if (event.srcElement) {   //soportado en IE8-
        sourceElement = event.srcElement;
     } else {
        sourceElement = event.target;   //soportado en IE9+ y otros
     }
     return event.type + " " + event.clientX + " " + event.clientY + " " +
     sourceElement.type + " " + sourceElement.tagName;
  }

- Utilizar event bubbling para evitar asignar manejador en muchas ocasiones.
- Se puede activar event capturing poniendo el último parámetro del
  método .addEventListener a TRUE. Si es FALSE, se produce event
  bubbling. Se pueden activar los dos si se añade dos veces el manejador con
  los valores distintos para el último parámetro.
- Cancelar event bubbling:
  event = event || window.event;  //por compatibilidad con IE8-
  if (event.stopPropagation) {
    event.stopPropagation();  //IE9+ y otros
  } else {
    event.cancelBubble = true;  //IE8-
  }

- Evitar funcionamiento por defecto del navegador (click botón derecho,
  pulsar enlace):
  <body oncontextmenu="return false">
  document.oncontextmenu = deshabilitaPorDefecto;

  function deshabilitaPorDefecto(event) {
    event = event || window.event;
    if (event.preventDefault) {  //IE9+ y otros
      event.preventDefault();
    } else {
      event.returnValue = false;  //IE8-
    }

  Prevenir que un enlace nos lleve a otra página:
  <a href="http://www.google.com" onclick="return false" >Google</a>
  <a href="http://www.google.com" onclick="deshabilitaPorDefecto(event)">
  Google
  </a>

- Detectar el botón del ratón pulsado:
  <input type="button" value="Click me" onmouseup="obtenerClickRaton(event)" />
  function obtenerClickRaton(event) {
    var botonPulsado;
    if (event.which)  {
      botonPulsado = event.which;  //IE9+ y otros
    } else {
      botonPulsado = event.button;  //IE8-
    }
  }

- Ventanas emergentes:
  window.open(URL, nombre, caracteristicas, reemplazar);
  <input type="button" value="Abrir ventana"
  onclick="window.open('http://www.google.com', '_self ', 'height=100,width=150',
  false)" />

  var ventana;
  function abrirVentana() {
    ventana = window.open("http://www.google.com", "ventana", "height=100,
    width=100");
  }
  function cerrarVentana() { ventana.close(); }


- Expresiones regulares:
  Herramienta gratuíta: Expresso Librería de expresiones: Regexlib
  var valor= document.getElementById("txtCadena").value;
  var resultado = valor.match(/\d+/g);
  if (resultado != null) {
    for (var i=0; i<resultado.length;i++) {
      document.getElementById("txtResultado").value += resultado[i] + "\r\n";
    }
  }
    \d: valor numérico (\d+: 1 o varios elementos numéricos consecutivos)
    /g: búsqueda global
    \d{5,}: números de 5 dígitos o más ---  \b\d{4}\b:  números de justo 4 dígitos
    [0-9]{5}: equivalente al anterior
    \b[a-zA-Z]\b: palabras con letras sin tilde
    [a|b|c]: busca cualquiera de los caracteres incluídos

  var cadena="Cadena con números: 10 11 222";
  cadena.match(/\d+/g); //g: global, i: insensible a mayúsculas y minúsculas,
  m: multilínea
  cadena.replace("/\d+/g, "XXX");  //reemplaza números por XXX
  cadena.split("/\d+/");
  var posicion = cadena.search(/\d+/);

  var regexp = /\d+/g;   //expresión regular literal (mejor rendimiento si
  la expresión regular no varía)
  var regexp = new RegExp("\\d+", "gim");  //global, ignore case, multiline
  regexp.exec(cadena);  //busca coincidencia y devuelve la primera encontrada
  regexp.test(cadena); //busca coincidencia y devuelve true o false
  regexp.toString();  //devuelve cadena con la expresión regular
  regexp.global; regexp.ignoreCase; regexp.multiline; regexp.source;

- Validación lado cliente:
  function validarLogName() {
    var txtName = document.getElementById("txtName");
    var name= txtName.value;
    var regExName = /[a-zA-Z0-9]+/;

    txtName.style.color = "white";
    if (regExName.text(name))
      txtName.style.backgroundColor = "green";
    else
      txtName.style.backgroundColor = "red";
  }

- Herramientas para reducir código Javascript (minification):
  - http://crockford.com/javascript/jsmin
  - https://marijnhaverbeke.nl/uglifyjs (online)