La jerarquía del lenguaje se divide en:


Tipos de Datos

JS no tiene tipos de datos, pero sí se pueden distinguir cinco categorías de tipos de datos implícitos:

Valores Numéricos

Enteros de 32 bits en decimal, octal (0...) o hexadecimal (0x...). Ej.: -25, 0777, 0xFF.

Reales en notación normal o científica. Ej.: 35.709, -1.045e7

Strings

Entre comillas (") o apóstrofos ('). Permite apótrofos dentro de comillas y viceversa. Cadena vacía "" o ''.

Secuencias de escape: \t (horiz tab, ASCII 9), \n (return), \r (line feed, ASCII 13), \f (form feed, ASCII 10), \b (backspace).

El carácter '\' también se utiliza para anular el significado que tienen determinados caracteres: \' (carácter apóstrofo), \" (carácter comillas). El carácter '\' al final de una línea anula el significado del carácter de salto de línea, lo que sirve por ejemplo para continuar una cadena en la línea siguiente.

Valores Lógicos

Valores true y false. En realidad JS los convierte internamente a 1 y 0 respectivamente, pero se recomienda no utilizarlo (incluso cualquier valor distinto de 0 es interpretado como true).

El valor null

Una expresión con una variable no inicializada da error, pero si la variable se inicializa a null, asume los valores 0, "" o false según se convierta a número, cadena o lógico.

Conversión de Tipos

En las conversiones implícitas, siempre intenta convertir de izquierda a derecha. Así, 5+"10"=15 (suma), "Hola"+10="Hola10" (concatenación), pero 5+"Hola" da error. Podemos observar que el operador "+" está sobrecargado (overloading).


Variables

Dintingue mayúsculas y minúsculas. Deben comenzar por letra, subrayado (_) o dólar ($), seguido de letras, números y subrayados (_). En principio nombres de cualquier número de caracteres. Como siempre, se recomienda seguir la Notación Húngara. Ej.: nSumaTotalBeneficios, sTituloVentana.

La sintaxis para declarar una variable es:

    var nombre [= expresión|null] [,...]

Si no se inicializa una variable, tiene un valor especial: undefined. En realidad no es necesario declarar las variables, pero se recomienda declararlas siempre. Por otra parte, al no existir tipos, es posible hacer x=10 y más tarde x="Hola", pero no es una buena práctica.

Variables Globales y Locales

Cualquier variable no declarada que aparezca dentro o fuera de una función se considera global, aunque para que sea conocida debe ejecutarse la sentencia en la que aparece dicha variable. Por eso es una mala práctica no declarar las variables.


Sentencias y Operadores

Sentencias

Cada sentencia termina en final de línea, pero se pueden incluir varias sentencias en una misma línea separadas por ";". En cualquier caso, es recomendable terminar todas las sentencias con ";" para evitar confusiones. Distingue entre mayúsculas y minúsculas.

Operadores

Aritméticos
+Suma, Concatenación (o Positivo unario)
-Resta (o Negativo unario)
*Multiplicación
/División
%Módulo
++Pre/postincremento (unario)
--Pre/postdecremento (unario)
Lógicos
==, !=Igualdad, Desigualdad
<,<=, =>, >Menor/Mayor/Igual
!Negación
&&, ||Relacionales
?:Condicional (ternario)
,Concatenación Lógica
De Bits
&, |AND, OR
^XOR
~NOT (complemento a 1)
<<, >>, >>>Desplazamiento Izdo., Dcho. y Dcho. Sin Signo
De Asignación y Agregación
=Asignación
op=Agregación (+ - * / % & | ^ ~ << >> >>>)

Operadores Aritméticos

El operador "+" también funciona como Operador de Concatenación de Cadenas.

El tipo del resultado de una expresión promociona para obtener la mayor precisión, excepto en el caso de la división entera. Así, 10/4=2, mientras que 10/4.0=2.5.

El signo del resultado del módulo siempre es el mismo que el cociente. Así, si -21/4=-5, entonces -21%4=-1.

Operadores Lógicos

Operadores de Igualdad y Desigualdad

Comparan enteros, reales o cadenas (distinguen mayúsculas y minúsculas), pero se recomienda no utilizarlos con reales. Ej.: if (z == 3.0) podría devolver un resultado distinto dependiendo de cada máquina.

Operadores de Comparación Menor/Mayor/Igual

Comparan enteros, reales o cadenas (distinguen mayúsculas y minúsculas). En el caso de cadenas, una cadena es menor que otra si va antes alfabéticamente.

Operador de Negación

Invierte el resultado de una comparación.

Operadores Lógicos de Relación

Permiten combinar varias expresiones de comparación

Evaluación "cortocircuito"

JS deja de evaluar una expresión lógica en cuanto conoce el valor resultante de la misma. Así, la expresión if (x == 5 && y == 6 && z == 7) dejará de evaluarse en cuanto no se cumpla alguna de las tres comparaciones (ya que en ese caso el resultado será falso), y la expresión if (x == 5 || y == 6 || z == 7) dejará de evaluarse en cuanto se cumpla alguna de las tres comparaciones (ya que en ese caso el resultado será cierto).

Comparación Difusa

En el caso de comparaciones de igualdad o desigualdad de reales, en vez de hacer if (x != 3.0, se podría utilizar if (x-3.0) < epsilon || (3.0-x) < epsilon, siendo epsilon un valor pequeño, por ejemplo 0.001. De todas formas lo mejor es no realizar este tipo de comparaciones con reales.

Operador condicional y operador coma

Operador condicional: condición ? expr_si_cierto : expr_si_falso devuelve la primera expresión si la condición es cierta y la segunda si es falsa.

Operador coma: expr1, expr2, ..., exprn evalúa todas las expresiones y devuelve el resultado de la última.

Operadores de Bits

Siempre se deben utilizar con números enteros.

El operador "<<" equivale a multiplicar por 2, y el operador ">>" equivale a dividir por 2. El primero rellena con ceros por la derecha, mientras que el segundo rellena con el bit de signo por la izquierda. El operador ">>>" equivale a ">>" pero rellenando con ceros por la izquierda (se pierde el signo).

Operadores de Asignación y Agregación

Los operadores de agregación son más eficientes. Así, x += 10 es más eficiente que x=x+10 porque en el primer caso sólo se accede una vez a la dirección de la variable "x" en memoria.

Orden de Evaluación

Comentarios

Estilo C con /* ... */ (varias líneas) o estilo C++ con //... (hasta fin de línea).


Estructuras de Control

Las estructuras de control permiten ejecutar una instrucción o un bloque de instrucciones {...} bien sea de forma condicionada o bien de forma repetitiva.

La sentencia if

    if (condición)
      ...
   [else
      ...]

La sentencia while

    while (condición)
      ...

La sentencia for

    for ([lista_inicializaciones]; [condición]; [lista_actualizaciones])
      ...

La sentencia break

Termina inmediatamente la ejecución de un bucle.

La sentencia continue

Termina inmediatamente la iteración actual.


Funciones

    function nombre([lista_parámetros_por_valor])
    {
      [var lista_variables_locales;]
      ...
      [return valor_devuelto;]
    }

El nombre sigue los mismos convenios que para las variables.

Almacenar las Funciones

Las funciones se pueden crear en un fichero (normalmente con extensión .js) y cargarse cuando sean necesarias mediante el atributo SRC="fichero.js" del tag SCRIPT.

Cuando se utiliza una librería de funciones en un "frame", todos los demás "frames" disponen automáticamente una variable llamada funcs que hace referencia al "frame" que contiene las funciones. Así, desde otro "frame" se podría llamar a una función de la librería en la forma funcs.función(...).


Objetos

Un objeto consta de "propiedades" (variables internas) y "métodos" (funciones internas), y puede producir "eventos".

En principio todas las propiedades y métodos son públicos, aunque algunas propiedades son de sólo lectura (no se les puede asignar un valor). Para acceder a una propiedad o llamar a un método se utiliza la forma:

    objeto.propiedad
    objeto.método(lista_argumentos)

Nota: aquí habla de "Objetos" e "Instancias de Objetos" en lugar de "Clases" e "Instancias de Clases".

Definir Objetos y Crear Instancias

Definir un objeto (clase) consiste simplemente en definir el "constructor de la clase" y definir todas sus propiedades mediante el cualificador this. Ej.:

    function house(rms, stl, yr, gar)
    {
      this.rooms = rms;     //number of rooms (integer)
      this.style = stl;     //style: Colonial, Tudor, Ranch (string)
      this.yearbuilt = yr;  //year built (integer)
      this.hasgarage = gar; //has a garage? (boolean)
    }

Es obligatoria la utilización de this, ya que en otro caso se interpretarían como variables locales. No es obligatorio declarar parámetros en el constructor: bastaría con inicializar las propiedades con unos valores por defecto.

Para crear instancias:

    var Casa1=new house(); //Todas las propiedades "undefined".
    var Casa2=new house(10, "Colonial", 1989, true); //Todas definidas.
    var Casa3=new house(10, "Colonial"); //Estilo y garaje "undefined".
    var Casa3=new house(10, , 1980, 1); //¡ERROR!
    var Casa3=new house(10, null, 1980, 1); //Estilo con valor "null".
    var Casa3=new house(10, "", 1980, 1); //Estilo con valor "".

Objetos y Arrays

Los arrays se definen mediante la clase Array:

    var nombre=new Array(número_de_elementos)

El índice comienza en cero. Los elementos pueden ser de distinto tipo y de cualquier tipo, incluso objetos, y se asignan como cualquier otra variable. Incluso se pueden definir nuevos elementos sobre la marcha:

    var a=new Array(3);
    a[0]="Juan"; a[1]="Pedro"; a[2]="Rosa";
    ...
    a[3]="Javier"; a[4]="María"; //¡Nuevos elementos!

Las propiedades de un objeto se almacenan en forma de array. Ej.:

    var Casa=new house(10, "Colonial", 1989, true);
    for (var i=0; i != 4; i++) //Escribir las 4 propiedades.
        document.write(Casa[i], "  ");

Es posible acceder al array de propiedades no sólo por índice, sino también por nombre de propiedad. Ej.:

    var Casa=new house(10, "Colonial", 1989, true);
    document.write("Nº de habitaciones: ", Casa["rooms"]);
    document.write("Garaje: ", Casa["hasgarage"] ? "Sí" : "No");

Instancias Extendidas y Arrays de Longitud Variable

Es posible añadir nuevas propiedades a una instancia sin más que asignar nuevos valores:

    var Casa=new house(10, "Colonial", 1989, true);
    var Casa1=new house(8, "Ranch", 1990, true);
    Casa.nbath=2; //Nueva propiedad posición 4: nº de baños.

Esta propiedad no afecta a Casa1 ni a cualquier nueva instancia de house que se cree. Por supuesto, esto es una mala práctica que no se debe utilizar.

Debido a que un objeto es un array de propiedades, es posible definir una clase con un número variable de propiedades, es decir, un array de longitud variable:

    function stringarr(howmany, initstr)
    {
      this.length = howmany; //Elemento 0 con el nº de elementos.
      for( var i = 1; i <= howmany; i++ )
        this[i] = initstr;  //Todos con el mismo valor inicial.
    }
    ...
    aStr = new stringarr(10, "spoon"); //10 cucharas...
    ...
    //Añadir nuevos elementos:
    aStr[101] = "I'm";
    aStr[102] = "doing";
    aStr[103] = "laundry";
    aStr.length += 3;

La sentencia for...in

Permite recorrer los nombres de todas las propiedades de una instancia:

    for(var p in Casa)
      document.write("Propiedad ", p, "con valor ", Casa[p], "
");

Métodos

Los métodos se declaran como propiedades, asignando a las mismas el nombre de una función definida aparte. La función puede tener o no el mismo nombre que el método. Dentro de la función se hace referencia al objeto mediante el cualificador this:

    function house(rms, stl, yr, gar) //Clase "house".
    {
      this.rooms = rm; this.style = stl;
      this.yearbuilt = yr; this.hasgarage = garp;
      this.show = showhouse; //Método "show()"
      this.howold = howold; //Método "howold()"
    }
    function showhouse() //Escribir valores.
    {
      for(var p in this)
      {
        //No mostrar los métodos.
        var s=""+this[p]; //Convertir a cadena.
        if (s.substr(0, 8) != "function")
          document.write("<B>", p, ": </B>", this[p], "<BR>");
      }
    }
    function howold(curyear) //Edad de la casa.
    {
      return curyear-this.yearbuilt;
    }

Objetos Anidados

Una propiedad de un objeto puede a su vez contener una instancia de otro objeto. Así, document es una propiedad de window que contiene el documento que aparece en la ventana, window.document, y a su vez se puede acceder a las propiedades y métodos de dicha instancia: window.document.bgColor, window.document.write(), etc.

La sentencia with

Evita escribir "objeto." delante de cada propiedad. Es menos eficiente porque JS ha de resolver cada referencia a una variable para ver si se trata de una propiedad o de una variable local.

    with (instancia)
    {
      ...
      prop = expr;
      ...
      función(... prop ...);
      ...
    }

Funciones con Número Variable de Argumentos

Una función en JS se almacena en realidad como un objeto que tiene dos propiedades, a las cuáles se puede acceder dentro de la propia función:

La propiedad arguments permite por tanto llamar a una función pasando todos los argumentos que se deseen. Ej.:

    function Resultado(sMsj) //Devuelve cadena "sMsj: suma".
    {
      var nSuma=0;
      /* Sumar argumentos (excepto el 0 que es sMsj) */ 
      for (var i=1; i != Resultado.arguments.length; i++)
        nSuma += Resultado.arguments[i];
      return sMsj + ": " + nSuma;
    }

Acciones y Eventos

El usuario puede realizar una acción sobre un objeto de una página HTML. El objeto reacciona produciendo un determinado evento al cuál es posible asociar una función o manejador que se ejecutará automáticamente al producirse dicho evento.

Acciones y Eventos de Navegación

En todos estos casos se carga o descarga una página, produciéndose los correspondientes eventos load y unload.

Otros eventos relacionados son mouseover, al situar el puntero sobre un enlace, y statechange, que indica que un objeto está realizando alguna operación pero aún no está listo para visualizarse (por ej., se está cargando un plug-in de vídeo pero aún no está listo para visualizarse).

Acciones y Eventos de Formularios

Elementos de tipo Botón

Existen cinco tipos de botones:

Algunos eventos son click, al hacer clic en el botón, y submit, al enviar el formulario mediante el botón Submit.

Los botones ocultos no producen eventos

Elementos de tipo Texto

Existen tres tipos de cuadros de texto:

Algunos eventos son: change, al modificar su contenido, select, al seleccionar texto, focus, al situarse en el campo (el campo obtiene el "foco" de atención), y blur, cuando el campo pierde el "foco".

Los campos de tipo Password no producen eventos para evitar el acceso a los mismos.

Elementos de tipo Lista

Producen los eventos focus, blur y change. Da igual que sean normales o de selección múltiple

Acciones que no son Eventos

Desplazar (scroll) una ventana, leer un grupo de noticias, responder un e-mail, crear una entrada en favoritos, redimensionar o mover la ventana, etc.: ninguna de estas acciones afecta a la página actual.

Utilizar los botones Atrás, Adelante o Inicial del navegador no son realmente eventos de JS, pero generan eventos asociados a la página actual ya que descargan ésta.


Manejadores de Eventos

Dado un elemento HTML (definido en su correspondiente tag) y dado un determinado evento que puede producir dicho elemento, para asociar una función o manejador a dicho evento se añade un nuevo atributo en el tag con el nombre onEvento, con la siguiente sintaxis:

    <elemento ... onEvento="código_en_línea|función([argumentos])"> 

Los eventos se pueden producir a tres niveles: a nivel de documento, a nivel de formulario y a nivel de elemento de formulario.

Manejadore de Eventos a Nivel de Documento

En el tag BODY se pueden definir manejadores mediante los atributos onLoad y onUnload.

También se puede considerar a nivel de documento el tag A con el atributo onMouseOver cuando se sitúa el puntero sobre un enlace, y el atributo onClick cuando se selecciona el enlace.

Manejadores de Eventos a Nivel de Formulario

Atributo onSubmit en el tag FORM (también se podría hacer con el atributo onClick en el botón Submit del formulario). La función de evento ha de devolver true o false según haya o no que enviar el formulario.

Manejadores de Eventos a Nivel de Elementos de Formulario

En los botones, atributo onClick; en los cuadros de texto, atributos onFocus, onBlur, onSelect y onChange; en los cuadros de lista, atributos onFocus, onBlur y onSelect.



Pruebas clase "house"