domingo, 9 de septiembre de 2012

CSS: Pseudo-clases y pseudo-elementos

Los pseudo-elementos y las pseudo-clases se definen para poder aplicar estilos en algunos elementos, o partes de un elemento, en casos especiales que no quedan cubiertos con los selectores habituales. Nos permiten seleccionar, por ejemplo, la primera letra de una línea, la primera línea de un párrafo, un link cuando ya ha sido pulsado, etc.
La sintaxis es la misma en los dos casos:

 a:visited {
 /*esto es una pseudo-clase*/
 }

p:first-line {
 /*esto es un pseudo-elemento*/
 }
 
CSS3 introduce una diferencia, recomienda utilizar “::” para los pseudo elementos, para diferenciarlos de las pseudo clases:

 a:visited {
 /*esto es una pseudo-clase*/
 }

p::first-line {
 /*esto es un pseudo-elemento*/
 }
 
De todas formas el mismo estándar especifica que los navegadores deben continuar soportando la notación anterior para evitar problemas de compatibilidad con código CSS antiguo, al menos para los pseudo-elementos definidos en CSS1 y CSS2 ( :first-line, :first-letter, :before and :after ).

pseudo-clases

Seleccionan un elemento que cumple alguna condición o estado determinado, por ejemplo un link cuando el ratón está encima ( a:hover) o un elemento cuando es el primero dentro del elemento padre ( li:first-child). Podría ser similar a aplicar una clase temporal a un elemento en un estado determinado.

Pseudo-clases especificas para enlaces :link y :visited

 
 a:link { color: blue; }
 
Aplica a todos los enlaces que todavía no han sido visitados. Aparecerían en color azul.
 
 a:visited { color: red; }
 
Aplica a los enlaces que ya han sido visitados. Aparecerían en color rojo.

Pseudo-clases dinámicas :hover, :active, :focus

Permiten cambiar el estilo en respuesta a alguna acción del usuario. Se utilizan a menudo en los enlaces, como las anteriores, pero pueden utilizarse en otros elementos.
 
 button:hover { color: green; }
 
Define un estilo que se muestra mientras el cursos está sobre el elemento. Es muy utilizado en enlaces y botones para hacer un ligero cambio de estilo que muestra claramente sobre que opción del menú nos encontramos.
 
 a:active { color: orange; }
 
Define un estilo diferente durante el momento en el que el elemento está siendo pulsado.
input:focus{ background-color:yellow; }
Se aplica a un elemento cuando recibe el foco.

:first-child

Selecciona un elemento sólo cuando es el primer hijo del elemento padre. Por ejemplo, la siguiente declaración:
p:first-child { background:yellow; }

Se aplicará a todos los párrafos que sean el primer elemento dentro de un contenedor. Si tenemos varios divs para dividir la página en columnas, los primeros párrafos de cada columna aparecerán en amarillo.

Para hacer que el primer elemento de una lista aparezca siempre en rojo:
li:first-child{ color: red; }

Lenguaje :lang

CSS nos permite seleccionar un elemento basandonos en el lenguaje que se ha definido mediante el atributo lang ( lang=“es”). Si tuvieramos dos párrafos definidos de la siguiente forma:
 

Esto es una casa

This is a house

Podríamos seleccionarlos y darles estilos diferentes:
 
p:lang(es) { color: red; }
p:lang(en) { color: blue; }

Pseudo-classes de CSS3

El nuevo estándar añade una cantidad importante de pseudo-clases nuevas a las que dedicaré un post en detalle más adelante ( :target, :root, :empty, :only-child, :only-of-type, :last-child, :nth-child, etc).

pseudo-elementos

Permiten seleccionar ciertos ‘elementos virtuales’ que no existen como tales en el DOM, por ejemplo la primera linea de texto en un párrafo ( p:first-line) o la primera letra de una línea (p:first-letter).

:first-line y :first-letter

Permiten seleccionar la primera línea de un elemento y la primera letra de un elemento, respectivamente.

p:first-line { color: gray; }
p:first-letter { text-transform: uppercase; }
Estas dos reglas CSS harían que la primera línea de cada párrafo fuera siempre de color gris y que la primera letra de cada párrafo aparezca en mayúsculas.

Estos dos pseudo-elementos sólo pueden aplicarse a elementos de bloque y a celdas de una tabla. No pueden aplicarse a un span, por ejemplo.

:before y :after

Se utilizan para insertar contenido, generado en nuestro CSS, al principio o al final de un elemento existente. Podemos también definir el estilo de este nuevo contenido dentro de la misma regla.

La propiedad content sirve para definir el contenido nuevo que se añade.

Por ejemplo, si tenemos una lista de artículos, podriamos utilizar el siguiente código CSS para colocar una indicación de NEW delante y detras de los elementos nuevos:

 
li.new:before {
    content: "NEW - ";
    background-color: green;
}

li.new:after {
    content: " - NEW";
    background-color: green;
}

Todos los elementos de la lista a los que coloquemos la clase “new” apareceran con ese texto extra para llamar la atención.

Cuidado al colocarlos separados por comas

Al utilizar estos elementos en nuestra hoja de estilos conviene tener en cuenta que, si los colocamos en una regla de CSS junto con otros selectores, separados por comas, el navegador que no soporte el pseudo-elemento ignorará los siguientes elementos de la lista, sin aplicarles el estilo.

En el siguiente ejemplo:

p:last-child, p.special {
 /* mis estilos */
}

IE8 no soporta last-child ( de CSS3) por lo que salta al final de la lista y tampoco aplica el estilo a los párrafos p.special.

References:
W3C CSS2 Pseudo-elements and pseudo-classes

miércoles, 5 de septiembre de 2012

CSS: Para qué sirve vertical-align

Probablemente todos hemos intentado alguna vez utilizar vertical-align para centrar verticalmente un contenido ( por ejemplo, un texto ) dentro de un div.


En la imagen anterior, aunque apliquemos vertical-align: middle al div contenedor o al bloque de texto, no va cambiar nada. En los dos casos el navegador ignora esta propiedad porque no aplica a esta situación.

Entonces, ¿para qué sirve vertical-align?

Esta propiedad se define en el estándar CSS2 del W3C como aplicable sólo a elementos inline y table-cell. Esta es la razón por la que no funciona para centrar el ejemplo anterior, porque no puede aplicarse a elementos de bloque.

Además, por si el nombre no era ya bastante confuso, la propiedad tiene diferente significado según se aplique a elementos inline o a elementos con display: table-cell, por lo que veremos los dos casos por separado.

Los valores que puede tomar son:
Valores: baseline | top |  bottom | text-top | text-bottom | middle | sub | super | <porcentaje %> | <longitud (px, cm, etc)> | inherit

vertical-align para elementos inline

Sirve para establecer la posición vertical de un elemento con respecto a la línea en la que se encuentra.
En la siguiente figura podemos ver 6 líneas imaginarias que son importanes para entender lo que significa cada uno de los valores de esta propiedad:


Las líneas top y bottom quedan siempre por encima y por debajo, respectivamente, de todo el contenido. Si no hay imágenes, estas líneas pueden coincidir con text-top y text-bottom.

Las líneas text-top y text-bottom quedan por encima y por debajo, respectivamente, del punto más alto (o bajo) del texto, incluyendo símbolos y acentos.

La línea middle se coloca justo en el centro de la altura de las letras minúsculas (se toma la letra ‘x’ como referencia).

Baseline es la línea sobre la que se apoya el texto.

En los siguientes ejemplos veremos cómo se alinea una imagen y un texto (en gris) con respecto a una línea de texto sin modificar (en negro), al cambiarles el vertical-align.

El HTML sería este:
 
  This is the default linedefault alignment 
  


Al elemento <p> le pondremos un borde azul, a los dos elementos que modificaremos con el vertical-align les ponemos borde naranja y al texto por defecto del párrafo, un borde gris.

Sin ningún vertical-align, se vería así:


Para cada uno de los valores posibles de la propiedad tendríamos:

baseline


Este caso es igual a la imagen sin vertical-align que veíamoss arriba, porque este es el valor que se muestra por defecto. La baseline del texto en gris y la base de la imagen se alinean con la baseline del texto sin modificar del elemento padre ( el <p>).


top


La parte superior de los elementos se alinean respecto al punto más alto de la línea ( sea imagen o texto ).

 

bottom


La parte inferior de los elementos se alinean respecto al punto más bajo de la línea ( sea imagen o texto ).

text-top


Los elementos se alinean con el punto más alto del texto. Es importante tener en cuenta que quizá la letra que tiene el punto más alto en nuestra fuente no aparece en nuestro texto. Aun así, la colocación se realiza respecto a ese punto más alto. Las letras más altas normalmente son las mayúsculas acentuadas.


text-bottom


Caso apuesto a text-top, los elementos se alinean con la parte más baja del texto. No es lo mismo que baseline porque en este caso vamos más abajo, incluyendo las líneas que bajan por debajo de la línea de base ( letras como p, j, g, etc).


middle


En este caso el navegador trata de alinear el centro vertical de los elementos con el centro del texto del padre ( el párrafo <p>).

 Lo que los navegadores hacen es alinear el centro vertical del elemento (de su caja) con la línea de base ( baseline ) del texto del padre más la mitad de la altura de la x. Visualmente puede no ser exactamente lo que esperamos porque, al no haber letras con partes descendentes, parece un poco descentrado.

super


Se utiliza para posicionar algo como superíndice.

sub


Se utiliza para posicionar algo como subíndice.

porcentaje


Eleva la posición del elemento en el porcentaje indicado. Es un porcentaje de la altura de la caja del propio elemento que tiene el vertical-align, por eso la imagen y el texto están a alturas diferentes. El valor puede ser negativo, en ese caso la posición baja. El valor 0% corresponde a la baseline.

Longitud en pixels o otras unidades


Eleva la posición del elemento en las unidades indicadas (px, cm, etc). El valor puede ser negativo, en ese caso la posición baja. El valor 0 corresponde a la baseline.

vertical-align para celdas de una tabla o elementos con display:table-cell

En el contexto de celdas de una tabla esta propiedad tiene un significado diferente. Sirve para definir como se alinea verticalmente el contenido de una celda. En este contexto sólo aplican los valores middle, top y bottom.

Para celdas de una tabla ( <table> ) el valor por defecto es middle, pero para un div con display:table-cell, el valor por defecto es top.

La siguiente imagen muestra como queda un bloque de texto con cada uno de los valores:


















martes, 28 de agosto de 2012

Los scripts externos pueden bloquear una web

Cuando cargamos un fichero JavaScript externo mediante una etiqueta <script> incluida en nuestro HTML, estamos corriendo un riesgo importante. Ese script externo a nuestra aplicación, probablemente un banner de publicidad o un widget, puede bloquear nuestra página y dejarla en blanco durante varios minutos o incluso evitar que llegue a cargarse. Steve Souders explica el problema en su presentación “Your script just killed my site” y proporciona una demostración online.

En la siguiente imagen podemos ver al menos tres elementos que se cargan mediante javascript externo en una página web real:



Si el código que incluimos para cargar estos elementos (normalmente proporcionado también por la empresa externa) no es apropiado, puede bloquear nuestra web.

¿Porqué un simple script puede bloquear nuestra página?

Un archivo JavaScript puede cargarse de manera síncrona (bloqueante) o asíncrona (no-bloqueante). Veamos que implica cada una:


Carga síncrona (bloqueante)

Decimos que se carga de forma síncrona cuando el navegador tiene que esperar a que el archivo se haya descargado y ejecutado para continuar presentando elementos en la página. Esto ocurre cuando utilizamos una etiqueta <script> incluida en el HTML. Al encontrarla, el navegador no continua calculando y mostrando los siguientes elementos de la página, este proceso se para hasta la ejecución del fichero. Esto ocurre para todos los navegadores.

La razón por la que se bloquea es que este script, al estar incluido de forma estática en el HTML, se considera parte de la página que se está presentando y, por lo tanto, el javascript que contiene puede crear nuevos elementos en la página ( o modificarlos si se carga en el body). Se espera a ejecutarlo completo para poder presentar la página correctamente.

Carga asíncrona (no-bloqueante)

La carga es asíncrona cuando el proceso de carga se realiza sin bloquear la presentación de otros elementos de la página.

Podemos conseguir la carga no-bloqueante mediante la inserción dinámica de la etiqueta <script> o utilizando atributos como  “defer” o “async”  (HTML5). Veremos después en detalle estas opciones.

El problema con los scripts externos que pueden "matar" nuestra página, es que a veces se incluyen de forma síncrona. Si el archivo es grande va a retrasar siempre la carga de la web que lo incluye. Aunque el archivo no sea pesado, su servidor puede ser lento, estar caído, o incluso estar bloqueado ( en China, por ejemplo ). Hasta que el script no se reciba o se produzca un timeout (si lo hay) nuestra página aparecerá en blanco.


¿Qué significa exactamente no-bloqueante?


Puesto que javascript no es multi-hilo, es imposible que dos scripts se ejecuten en paralelo. Este thread es además el mismo que se encarga de renderizar los elementos de la página. Cuando hablamos de un script no-bloqueante significa que no bloquea la página (puede seguir con el renderizado de elementos del DOM) mientras se descarga, la ejecución siempre se va a realizar como tarea única, nunca en paralelo.

Tenemos entonces que el navegador tiene que realizar dos tareas con el archivo:
  1.  Descargarlo de la URL que se le indique 
  2.  Ejecutarlo
El punto 1 es normalmente el que más tiempo requiere y es el único que podemos optimizar mediante estas técnicas. La ejecución siempre va a ser bloqueante puesto que tenemos un solo hilo que se encarga de ejecutar y de presentar elementos del UI.

Formas de carga no-bloqueante


Etiqueta <script> generada dinámicamente

Lo más habitual es utilizar una etiqueta <script> que se genera dinámicamente con JavaScript. Cuando se crean de este modo, la descarga se realiza inmediatamente pero no bloquea el renderizado de otros elementos. El fichero se ejecuta cuando se ha descargado completamente:
var script = document.createElement("script");
script.type = "text/javascript";
script.src = “/path/to/script.js";
document.getElementsByTagName("head")[0].appendChild(script);
Hay que tener en cuenta que esta técnica no respeta el orden de inclusión de varios ficheros JavaScript (en algunos navegadores). No se garantiza que el fichero que se incluye primero sea el primero en ejecutarse.

Atributo ‘defer’ en <script>

Incluyendo el atributo defer la descarga comienza inmediatamente pero de forma no-bloqueante. La ejecución se retrasa hasta que la página se ha parseado completamente.


Atributo ‘async’ en <script> ( HTML5 )

En HTML5 se ha creado un atributo nuevo precisamente para este propósito:
de esta forma la etiqueta <script> se comporta igual que si la hubiéramos generado dinámicamente. El script de descarga inmediatamente sin bloquear la presentación de la página y se ejecuta en cuanto está descargado (esta es la principal diferencia respecto a defer).

Es importante señalar que todas estas técnicas retrasan el evento onload hasta que los scripts se han ejecutado. Existen otras técnicas que utilizan XHR (AJAX) o iframes, pero no aportan ventajas con respecto a las anteriores y prácticamente han sido desplazadas por estas.


Referencias:
Best way to load external javascript
Cargar JavaScript. Blocking vs non-blocking
Loading Scripts Without Blocking
What is a non-blocking script?


viernes, 24 de agosto de 2012

CSS: elementos de bloque y elementos en línea

Un elemento HTML se puede mostrar como elemento de bloque ( display: block ) o como elemento en línea ( display: inline ). Comprender exactamente la diferencia entre estos dos tipos de presentación es fundamental para un desarrollador.

Elementos de bloque ( block )

Elementos de bloque son, por ejemplo: <p>, <div>, <ul>, <li>, <form>, etc (siempre que no cambiemos su display por defecto).
Se caracterizan por:
  • Se colocan siempre en su propia línea, debajo de los elementos anteriores
  • Se expanden hasta ocupar toda la anchura disponible ( la del elemento padre )
  • La altura se ajusta al contenido
  • Pueden contener otros elementos inline o block
  • Se les puede fijar altura y anchura con CSS ( width y height )
  • Se les puede asignar margin y padding con CSS
  • Ignoran la propiedad CSS vertical-align


Elementos en línea ( inline )

Elementos en línea son, por ejemplo: <a>, <span>, <b>, <em>, etc (siempre que no cambiemos su display por defecto).
Se caracterizan por:
  • No crean una nueva línea. Se colocan ‘en línea’ con otros elementos
  • Su anchura y altura se ajusta al contenido y no podemos cambiarlas con CSS ( ignora widht y height )
  • Sólo podemos fijar margin-left y margin-right. Ignoran margin-top y margin-bottom 
  • Sólo pueden contener otros elementos inline
  • Debe respetar la propiedad white-space de CSS
  • Respeta vertical-align


Particularidades de margin y padding para elementos inline

El padding y el margin para elementos inline puede aplicarse en los cuatro lados, pero el que se define arriba y abajo no va a afectar a otros elementos, no los desplaza. Es como si ignorara estos valores, pero podemos apreciar el padding aplicado si definimos un borde o un color de fondo:


Imágenes y elementos inline-block

El elemento <img>(imagen) es un poco especial porque se comporta como una mezcla de elemento en línea y elemento de bloque:


Realmente es un elemento inline, pero de un tipo especial que admite altura y anchura. En el estándar se define como ”elemento en línea reemplazado” ( replaced inline element ) y para estos elementos width y height sí aplica.

Se define como un elemento reemplazado porque no tiene contenido por si mismo, sino que será despues reemplazado por el archivo que se obtiene de su URL.

Existe un tipo de display para hacer que cualquier elemento se comporte como lo hacen las imágenes, como un elemento de bloque que se coloca en línea:

display: inline-block

Para elementos reemplazados ( como <img> ) display: inline-block es exactamente igual al display: inline que tienen por defecto.

Referencias:
Inline elements and padding
W3C CSS2 Visual formatting model

sábado, 23 de junio de 2012

El patrón Singleton en Javascript

El patrón singleton se utiliza cuando queremos que exista una sola instancia de una clase particular en toda la aplicación. Cuando alguien instancia una clase singleton debemos comprobar si ya existe una instancia y, si es así, devolver esa instancia. Si no existe, se crea.

 Esta definición encaja muy bien en los lenguajes con una orientación a objetos clásica, como Java, pero JavaScript no tiene clases, su orientación a objetos se basa en prototipos. Esta particularidad, junto con el uso de funciones constructoras para crear algo parecido a una clase, hace que este patrón pueda implementarse de muchas maneras diferentes.

El singleton como un objeto literal

Puesto que el objetivo es que solamente exista un objeto concreto de un tipo ¿ porqué no crearlo directamente ?. En JavaScript podemos crear objetos sin necesidad de tener una clase ni un constructor. Esta es la forma más sencilla de crear un singleton:

var mySingleton = {
 property1: 1,
 property2: 2,
 method1: function() {}
};

Si necesitamos tener variables y métodos privados, podemos utilizar el patrón módulo para crear el objeto:
var mySingleton =  (function() {
 var privateProperty1 = "one";
 var privateMethod1 = function () {};
 return {
    publicProperty1: 1,
    publicProperty2: 2,
    publicMethod1: function() {
             //use private props and methods here
    }
 };

})();

Un singleton más clásico

También podemos implementar el patrón de una forma más parecida al patrón clásico, de forma que tengamos una 'clase' ( realmente una función constructora ) que no se pueda instanciar y con un método público 'getInstance' que nos devuelva el objeto si ya existe o lo cree si no está creado:

var mySingleton = (function() {

    //Singleton constructor is private
    function Singleton() {
        var privateVar1 = "I'm a private var";
        this.publicVar1 = "I'm a public var";
        this.publicMethod1 = function() {
            console.log("Private var: " + privateVar1 + " public var: " + this.publicVar1);
        }
    }

    //private var to store the single instance
    var singleInstance;

    //Return the object providing getInstance method
    return {
        getInstance: function() {
            if (!singleInstance) singleInstance = new Singleton();
            return singleInstance;

        }
    }

})()

En este caso, lo que tenemos en 'mySingleton' es un objeto que proporciona el método público 'getInstance'. Para conseguir la instancia hacemos:

var myInstance = mySingleton.getInstance();

 

Utilizando el operador 'new'

Podemos hacerlo aún más sencillo de usar, de forma que que el usuario no tenga que saber que está instanciando un singleton ( llamando a getInstance ). Puede hacer 'new' como con cualquier otra clase y obtener la instancia única.

Esta sería nuestra clase ( nuestra función constructora ):

function MySingleton () {
   if ( MySingleton.singleInstance ) return MySingleton.singleInstance;  
   MySingleton.singleInstance = this;
   this.publicProperty1 = 1;
   this.publicProperty2 = 2;
   this.publicMethod1: function() {};
} 

Podemos instanciar la clase con 'new' todas las veces que queramos, obtendremos siempre la misma instancia:

var mySingletonInstance1 = new MySingleton();
var mySingletonInstance2 = new MySingleton();
var mySingletonInstance3 = new MySingleton();
// mySingletonInstance1 === mySingletonInstance2 === mySingletonInstance3

Podemos mejorar aún más el código evitando usar una propiedad pública (MySingleton.singleInstance) para guardar nuestra instancia. Es mejor utilizar una variable privada de la siguiente forma:

var MySingleton = (function() {
   var singleInstance;
   return function() {
        if ( singleInstance ) return singleInstance;  
        singleInstance = this;
        this.publicProperty1 = 1;
        this.publicProperty2 = 2;
        this.publicMethod1: function() {};
    }   
})(); 

El uso sería igual que en el ejemplo anterior:

var mySingletonInstance1 = new MySingleton();
var mySingletonInstance2 = new MySingleton();
var mySingletonInstance3 = new MySingleton();
// mySingletonInstance1 === mySingletonInstance2 === mySingletonInstance3


domingo, 17 de junio de 2012

Ya no se diseña para una resolución concreta

Hace ya bastantes años, y durante mucho tiempo, la norma número uno del diseño de páginas web era:

"programa siempre para una resolución de 800x600 px"

Después la resolución 'objetivo' pasó a ser 1024px, que se traducía en diseños de 960px debido al ancho del borde del navegador y la barra de scroll y a que 960 es divisible entre 3, 4, 5, 6, 8, 10, etc, lo que hace fácil una maquetación en columnas.

Todo esto ha quedado obsoleto. Ya no tiene ningún sentido pensar ¿para qué resolución vamos a hacer esta página/aplicación?.

Ya no hay una resolución ni un dispositivo base para hacer un diseño

Cualquier usuario puede acceder a nuestra web con varios dispositivos diferentes, con tamaños muy distintos, y quiere reconocer la web cuando entra. No podemos crear una web completamente diferente para cuando entre con su móvil, otra para cuando entre desde un tablet, otra para PC, etc. El usuario quiere encontrar siempre la web que conoce.

La cantidad de dispositivos y tamaños con los que se puede acceder a nuestro contenido es incontrolable y crece cada pocos meses.

Debemos simplemente programar y diseñar de forma que el contenido se adapte al entorno del usuario y olvidarnos del control. Ya no podemos controlar nuestro diseño como si fuera para una revista. Es imposible controlar las medidas y ajustar el contenido 'al pixel' y esperar que se vea igual en todos los dispositivos posibles. El contenido se debe adaptar al dispositivo.

Si seguimos pensando en tamaños fijos y en una resolución objetivo, estamos viviendo en el pasado. El diseño adaptable (responsive design) no es una forma de hacer las cosas, es ya la única forma aceptable de trabajar para la web.

domingo, 3 de junio de 2012

Espacios de nombres en JavaScript (namespaces)

El manejo de espacios de nombres en JavaScript ha sido ignorado durante muchos años porque los programas eran relativamente sencillos y, normalmente, una página web no se componía de diferentes piezas de código desarrolladas por programadores o empresas diferentes. El código se incluía como un script en la página y la mayoría de las variables y funciones eran globales.

Actualmente, en JavaScript se programan aplicaciones muy complejas ( enormes a veces ) y se han desarrollado cientos de librerías que podemos importar en nuestro código. Esto hace necesario organizar de alguna manera nuestro código para asegurarnos de que nuestras variables, objetos y funciones sean únicas y no se estén sobreescribiendo ( o siendo sobreescritas ) por una variable del mismo nombre de alguna de las librerías externas que utilicemos. Nombres como getElement, counter, checkValue, showMessage, etc son muy comunes y podrían existir en casi cualquier script que importemos.

Para poder utilizar cualquier nombre con seguridad, cada programa debe definir sus variables dentro de un contenedor único. Este contenedor es el espacio de nombres (namespace).

Cada librería externa que utilicemos tendrá su propio espacio de nombres y nosotros debemos definir también el nuestro para nuestro proyecto.

¿Cómo se crea un espacio de nombres?


En JavaScript se utiliza un objeto como espacio de nombres porque no existe una sintaxis nativa para esta funcionalidad.

Por ejemplo, podemos definir el siguiente objeto:

var myProject = {};

y luego definimos nuestras variables y funciones como propiedades de este objeto:

myProject.var1 = "una variable";
myProject.var2 = "otra variable";
myProject.var3 = { uno: 1,
                   dos: 2 };
myProject.doSomething = function () { ... };

De esta forma la única variable global que definimos es myProject y todos los nombres que definimos en el proyecto estarán dentro de este contexto definido por nuestro espacio de nombres. Siempre accederemos a cualquier elemento con el prefijo myProject delante.

La forma de definir las variables dentro del objeto no importa, podemos hacerlo directamente al crearlo:

var myProject = {
    var1:  "una variable",
    var2 = "otra variable",
    var3 = { uno: 1,
             dos: 2 };
    doSomething = function () { ... }

}

o utilizar el patrón módulo para tener también propiedades privadas.

Comprobar si el espacio de nombres está creado


Antes de crear el espacio de nombres es necesario comprobar si ya está creado. Si el namespace ya está definido utilizaremos el objeto ya creado. Esto es especialmente importante cuando nuestra aplicación tiene varios módulos y utilizamos espacios de nombres anidados:

myProject.userInterface
myProject.ajaxHandler
myProject.eventManager

Normalmente cada módulo está en un fichero separado y no podemos hacer:

var myProject = {};
myProject.usrInterface = { 
    //module logic here
}

Porque si myProject ya existe estaríamos borrando todo lo que contenga (todos los otros modulos).

Una forma común de hacer la comprobación es:

var myProject = myProject || {};

o también:

myProject || ( myProject = {} )

En esta última expresión, la segunda parte sólo se ejecuta si myProject es false.

Una función para crear el espacio de nombres


Cuando el proyecto es muy grande puede haber varios niveles de anidamiento en el namespace:

myProject.ui.list
myProject.ui.userForm
myProject.utils.validateInput
myProject.core.ajaxHandler
myProject.core.eventManager
...

Cada módulo tendrá que comprobar, uno a uno, si existen los namespaces de nivel superior antes de crear el suyo. Es mucho más cómodo utilizar una función para crear un espacio de nombres concreto, que se le pasa como parámetro. Todas las comprobaciones quedan encapsuladas en la función.

function createNameSpace( nameSpaceString ) {
    var names = nameSpaceString.split(".");

    //global object is the parent for first level nameSpace
    var parent = window;  
    
    //if any nameSpace level doesn't exist, create it
    for ( var i=0, imax=names.length ; i < imax; i++ ) {
        if ( !parent[names[i]] ) parent[names[i]]={};
        parent = parent[names[i]];
    }      
}

Al principio de cada módulo crearíamos el espacio de nombres de esta forma:
createNameSpace( "myProject.core.ajaxHandler" );