lunes, 10 de junio de 2013

Conversión rápida de tipos en JavaScript

JavaScript puede convertir dinámicamente el valor de una variable de un tipo a otro, dependiendo del contexto. Por ejemplo, si hacemos la siguiente multiplicación:


var result = "4" * 2  // resultado 8 

En intérprete convertirá implícitamente el string "4" en un número porque entiende, por el contexto, que queremos multiplicar dos números.

A veces la conversión implícita es un problema y el resultado no es lo que queremos:


var result = "4" + 8  //resultado "48"

En este caso JavaScript considera que queremos concatenar dos strings. Convierte 8 en un string y devuelve "48". Sólo si los dos operandos son números se realizará la suma, si cualquiera de ellos es un string se concatenan.

Para todos los casos en los que la conversión automática puede darnos problemas, lo mejor es que nosotros forcemos la conversión a los tipos apropiados.

Utilizando constructores

Los tipos básicos ( boolean, string, number .... ) tienen un constructor asociado (por si queremos crearlos como objetos en vez de tipos primitivos). Podemos utilizar el constructor como una función para realizar la conversión explícita:


Number("4");     // 4
Number("Hola")   // NaN ( Not a Number)
Number("3 Hola") // NaN
Number(1e3)      // 1000 ( "e" significa exponente)

String(4);       // "4"
String(0.7);     // "0.7"

Boolean(4);      // true
Boolean(0);      // false
Boolean([1,2,3]) // true

Existen también las funciones parseInt() y parseFloat() para hacer la conversión de strings a números. Estos métodos los veremos en detalle en otra entrada.

Forma rápida de conversión de tipos

Doble negación para convertir a boolean

var myBooleanValue = !!8; // true

Concatenar un string vacío para convertir a string

var myStringValue = "" + 8; // "8"

'+' para convertir a número

Los strings son siempre convertidos en números automáticamente si actuan como operandos de una expresión matemática ( excepto para la suma, que también concatena textos ). Sabiendo esto, una forma rápida de convertir un string en un número es incluirlo en alguna operación que no modifique su valor, como restarle 0 o multiplicarlo por 1:


var myNumberValue = "8" - 0; // number 8
var myNumberValue = "8" * 1; // number 8
var myNumberValue = "8" / 1; // number 8

Sin embargo, lo que más se utiliza por su simplicidad es el "+" como operador unitario. En este caso el comportamiento de la suma sí está perfectamente definido y claro y sabemos con toda seguridad que convierte un string en un número:


var myString = "8"

var myNumberValue =  +myString  // number 8
var myNumberValue =  +"20"      // number 20

Esta conversión es la más rápida pero resulta en una notación un poco confusa. Puede confundirse con un intento erróneo de pre-incremento de una variable ( ++myVariable ). A veces se coloca entre paréntesis para intentar dejar más clara la conversión:


var myString = "8"

var myNumberValue =  (+myString)  // number 8

La conversión utilizando Number() es la más lenta de todas.

Resumiendo las opciones de conversión rápida:


//to boolean
var myBooleanValue = !!20; // true

//to string
var myStringValue = "" + 20; // "20"

//to number
var myNumberValue =  +"20"      // number 20



Fuentes:
Strings to Numbers
JavaScript, The Definitive Guide. Type Conversions
Type Conversion

viernes, 7 de junio de 2013

Detectar si una variable es un array en JavaScript

Para detectar el tipo de una variable normalmente utilizamos el operador typeof:

typeof "Hello";  //returns "string"
typeof 3;  //returns "number"

Este operador funciona bien para los tipos boolean, number, string y undefined, pero cuando la variable es un objeto ( por ejemplo un Array ) devuelve siempre "object":


typeof [];  //returns "object"
typeof {};  //returns "object"
typeof new Date(); //returns "object" 

El operador instanceof

Para conocer el tipo de objeto utilizamos el operador instanceof de la siguiente forma:

variable instanceof constructor;

De esta forma podemos preguntar si una variable es una instancia de Array, de Date, de algún constructor propio, etc.


var myArray = [];

myArray instanceof Array;  // true
myArray instanceof Number; // false
myArray instanceof String; // false
myArray instanceof Object; // true

En la última línea vemos que para un array, el operador también devuelve true en la comparación con Object. Esto es porque un array es una instancia de 'Array' y tambien de 'Object' porque el constructor Array hereda de Object.

Problemas si utilizamos multiples frames

La solución que hemos visto nos dará problemas si manejamos arrays creados en frames diferentes. Cada frame en una página tiene un entorno DOM propio y cada uno tendrá su propia clase 'Array' y 'Object'. Si intentamos hacer la comprobación con un array creado en otro frame:


arrayFromAnotherFrame instanceof Array;  // false

El resultado es false porque no es una instancia del constructor 'Array' de este frame.

El estándar de facto para detectarlo correctamente en todos los casos, propuesto por Juriy Zaytsev (Kangax), consiste en utilizar toString sobre el objeto y comprobar si devuelve "[object Array]":


function isArray(value) {
     return Object.prototype.toString.call(value) === "[object Array]";
}

ECMAScript 5 introduce Array.isArray()

La nueva versión de JavaScript introduce un método específico para detectar si un valor es un array:


var myArray = [];

Array.isArray( myArray );  // true

Soportado en IE9+, Firefox 4+, Chrome, Safari 5+ and Opera 10.5+.

Una buena solución si tenemos que dar soporte a navegadores antiguos es crear el método isArray si no existe:

if(!Array.isArray) {
  Array.isArray = function (value) {
    return Object.prototype.toString.call(value) === "[object Array]";
  };
}

Fuentes:
Perfection Kills: instanceof considered harmful

miércoles, 5 de junio de 2013

Tutorial de expresiones regulares en JavaScript

¿Qué son las expresiones regulares?

Una expresión regular es una forma de definir una 'plantilla', con una sintaxis propia, para localizar un patrón dentro de un texto. El ejemplo más sencillo sería definir una palabra como plantilla:

Expresión regular: /casa/

Encontraría la palabra casa en el texto:

La casa de la montaña.

La utilidad real se muestra cuando utilizamos caracteres especiales para crear patrones de busqueda mucho más complejos, del tipo:

Expresión regular: /\W*\s(\S)*$/

Parece mucho más complicado de lo que es en realidad. Sólo hay que aprender unas reglas básicas y unos cuantos caracteres especiales.

JavaScript tiene dos notaciones

En JavaScript hay dos formas de crear una expresión regular: mediante la notación literal o utilizando el constructor RegExp():


//notación literal
var myRegExp = /casa/g; /* /reg. expression/flags(g|i|m) */

//Usando el constructor RegExp
var myRegExp = new RegExp('casa','g'); /* RegExp('expression','flags(g|i|m)'); */

Las dos son equivalentes. La primera se compila cuando el script se carga y es más rápida. La segunda se compila en tiempo de ejecución por lo que es la única opción si la expresión contiene variables que tienen que ser interpoladas. En este tutorial utilizaremos la notación literal por simplicidad. Todas las explicaciones son válidas también para el constructor.

Para entender mejor el funcionamiento de las expresiones regulares conviene pensar en una busqueda caracter a caracter. Si tenemos el patrón 'casa', lo que estamos buscando no es la palabra casa, sino una 'c' seguida de una 'a' seguida de una 's', etc. Es mucho más facil entender el uso de los caracteres especiales de esta manera.

Por ejemplo, si sabemos que \s representa un espacio en blanco y que ? significa que el caracter anterior es opcional, ¿ que estamos seleccionando en la siguiente expresión regular?:

var myRegex = /\sglobos?/;

Estamos buscando un espacio en blanco, seguido de una 'g', de una 'l', de una 'o', de una 'b', de una 'o' y de una 's' que es opcional, puede aparecer o no. Por tanto seleccionaremos:

Un globo, dos globos, tres Globos.

Podemos ver que sólo ha seleccionado el primer 'globo'. Por defecto la búsqueda termina cuando se encuentra la primera coincidencia. Si queremos que siga buscando tenemos que utilizar el flag g.


Flags (g, i, m)

Los flags modifican el comportamiento por defecto de la búsqueda. Aparecen justo al lado de la barra que marca el final de la expresión regular y pueden ser:

  • g (global). Se busca siempre en el texto completo en vez de detenerse cuando encuentra la primera coincidencia con el patrón.
  • i (ignora Mayusculas). No diferencia mayúsculas y minúsculas.
  • m (multilínea). El texto incluye saltos de línea. ^ y $ se aplican a 'comienzo de línea' y 'final de línea', en vez de 'comienzo de texto' y 'final de texto'.

Si en la cadena de nuestro ejemplo queremos seleccionar también otras ocurrencias de la palabra 'globo', tenemos que utilizar:

var myRegex = /globo/g;
Un globo, dos globos, tres Globos.

La expresión encontraría dos coincidencias. El tercer 'Globo' no coincide con el patrón porque la G es mayúscula. Si añadimos el modificador i sí se seleccionará:

var myRegex = /globo/gi;
Un globo, dos globos, tres Globos.

La segunda y tercera aparición están en plural. Sería bueno que nuestra expresión regular capturara tanto globo como globos. Como ya vimos antes, podemos utilizar la ? para indicar que el carácter anterior es opcional:

var myRegex = /globos?/gi;
Un globo, dos globos, tres Globos.

?, + , *   Cuantificadores sobre el carácter anterior

Con estos tres caracteres extraños podemos indicar que el carácter inmediatamente anterior puede ser opcional, o que tiene que aparecer como mínimo una vez o que puede aparecer muchas veces.

?El carácter anterior es opcional. Aparece 0 ó 1 veces.
+El carácter anterior aparece una vez o más.
*El carácter anterior puede no aparecer, aparecer una vez o aparecer repetido muchas veces (aparece 0 o más veces).

Si tenemos el texto:

"Tengo un gloooooobo grande y tres globos pequeños."

¿Como podemos hacer para capturar los dos globos?. La expresión anterior no nos sirve porque la primera aparición quedaría fuera.

Necesitamos una expresión regular que nos seleccione cualquier patrón con una 'g' seguida de una 'l', seguida de una o más 'o', una 'b', una 'l', una 'o' y una 's' opcional.

var myRegex = /glo+bos?/gi;
Tengo un gloooooobo grande y tres globos pequeños.

En este caso, si ponemos * en vez de + también funcionaría. La diferencia es que el asterisco permite que el carácter no aparezca ( cero o más veces). Por lo tanto también seleccionaría glbo. Con + obligamos a que el carácter aparezca al menos una vez.

Para seleccionar todas las palabras en el siguiente texto:

"bo, boooo, b."

sólo nos sirve el *:

var myRegex = /bo*/g;
bo, boooo, b.

'.' Un comodín para un solo car.cter

El punto '.' es un comodín que puede sustituir a cualquier carácter excepto a un salto de línea.

La siguiente expresión:

var myRegex = /gat./gi;

capturará 'gat' seguido de cualquier carácter:

Gato, gata, gamo, gatuno, gatitos, gatoooooos, gatk, gallego, gat , gat.

En las dos últimas coincidencias podemos ver que también captura el espacio en blanco y el punto final.

{n,m} Cuantificadores más concretos

Con {n,m} podemos indicar exactamente el número de veces que aparece el carácter anterior o delimitarlo en un rango concreto ( por ejemplo que aparezca entre 3 y 5 veces).

{n}El carácter anterior aparece exactamente *n* veces.
{n,}El carácter anterior aparece *n* o más veces.
{n,m}El carácter anterior aparece un mínimo de *n* y un máximo de *m* veces

var myRegex = /r{2}/gi;
b, brr, brrr, brrrr.

En el último caso tenemos brrrr. Se seleccionan las dos primeras y despues las dos segundas.

var myRegex = /r{2,}/gi;
b, brr, brrr, brrrr.
var myRegex = /r{2,3}/gi;
b, brr, brrr, brrrr.

[abc] Conjuntos de caracteres

Para indicar que en un lugar de nuestra expresión puede aparecer cualquier de los caracteres de un conjunto concreto podemos utilizar [ ]. Por ejemplo, si queremos seleccionar 'sal', 'cal' y 'mal', podemos indicar que el primer caracter puede ser [scm]. Es decir, puede ser uno de los caracteres del conjunto:

var myRegex = /[scm]al/gi;
tal, sal, perro, mal, sota, cal, tal, salir, ramal.

También podemos negar el conjunto con el carácter ^, indicando que puede aparecer cualquier carácter menos los que están en el conjunto.

var myRegex = /[^scm]al/gi;
tal, sal, perro, mal, sota, cal, tal, salir, ramal.

Se puede especificar un rango mediante un guión: [0-7] indica números del 0 al 7, [a-z] indica letras de la 'a' a la 'z'

'^' y '$' Principio y final de línea

Muchas veces es necesario seleccionar una cadena sólamente si está al principio o al final de un texto. Por ejemplo, es muy común eliminar los espacios en blanco que puedan aparecer al principio o al final.

Sabemos que el símbolo \s selecciona un espacio en blanco. Con la siguiente expresión seleccionariamos todos los espacios al principio de un texto:

var myRegex = /^\s+/g;

Estamos buscando un 'principio de texto' seguido de uno ó mas espacios en blanco:

   Este es mi texto.

Si queremos seleccionar los del final:

var myRegex = /\s+$/g;

Estamos buscando uno ó mas espacios en blanco justo antes de un final de texto:

Este es mi texto.   

En el apartado de flags vimos que existe uno para modificar el comportamiento de estos dos carácteres. El flag 'm', cuando está presente indica que el texto es multilínea y queremos que ^ y $ seleccionen principio y final de cada línea, en vez de principio y final de texto.

\s, \d, \D, \w, \W .... Símbolos para hacer la vida más facil

Algunos conjuntos de caracteres son de uso tan común que se han creado unos símbolos para incluirlos más fácilmente. Por ejemplo, para indicar que un carácter debe ser un número podemos escribir [0-9] o podemos utilizar \d (digit) que es mucho más sencillo. Cuando el símbolo aparece en mayúscula significa exactamente lo contrario. \D sería cualquier carácter que NO sea un número.

Los más utilizados son:

\sCualquier tipo de espacio en blanco ( espacio, tabulador, salto de línea, etc)
\STodo carácter que NO sea un espacio en blanco
\tTabulador
\wCualquier carácter alfanumérico. Equivalente a [a-zA-Z0-9_]
\WCualquier carácter NO alfanumérico
\dUn dígito. Equivale a [0-9]
\DCualquier carácter que NO sea una dígito
\b'Word Boundary'. Marca el inicio o el fin de una palabra ( similar a '^' y '$' para una línea)

Como ejemplo podemos escribir una expresión para comprobar un nombre de usuario. Suponemos que el nombre de usuario no puede contener espacios y sólo puede contener números y letras (incluimos tambien el guión bajo o subrayado). Tiene que tener un mínimo de 6 carácteres y un máximo de 12:

var myRegex = /^\w{6,12}$/g;

Sólo seleccionará un nombre de usuario cuando cumpla las condiciones. En caso contrario no seleccionará nada. Puede utilizarse en una condición de JavaScript para aceptarlo o rechazarlo.

'|' OR

La barra vertical nos permite definir varias expresiones diferentes para buscar una o otra:

var myRegex = /perro|gato/gi;
perro, loro, gato, hamster, serpiente.

Se busca la coincidencia con la expresión de la de la derecha o de la de la izquierda completas. Si queremos que el OR sólo afecte a una parte de la expresión, tenemos que encerrar esa parte entre paréntesis. Por ejemplo, si queremos buscar 'elefante' y 'elemento'

var myRegex = /ele(mento|fante)/gi;
elegante, elemento, testamento, elefante, chanante, elemental.

Tambien podemos definir más de dos opciones:

var myRegex = /ele(mento|fante|gante)/gi;
elegante, elemento, testamento, elefante, chanante, elemental.

() Creando subexpresiones en nuestra regex

Los paréntesis se utilizan para marcar una parte de la expresión sobre la que actúa algún operador. En el ejemplo anterior vimos que podemos delimitar el rango sobre el que actuaba OR para que no se aplicara a la expresión completa. También podemos extender el rango sobre el que actuan los cuantificadores.

var myRegex = /1(23)+/gi;

En la expresión anterior el '+' se aplica al grupo completo '23'.

123, 1232323, 1232222, 123333333, 12323232323.

Sin los paréntesis los cuantificadores se aplican sólo al carácter inmediatamente anterior:

var myRegex = /123+/gi;
123, 1232323, 1232222, 123333333, 12323232323.

Los paréntesis tienen también otra función: memorizan todas las coincidencias que se encuentren en el texto y pueden utilizarse despues como $1, $2, $3, etc. Sólo se memoriza y guarda (en $n) la parte de la expresión marcada con los paréntesis. Por ejemplo, en una expresión que seleccione fechas, podemos encerrar entre parentesis la parte que coge el dia y el mes y luego cambirlo de orden colocando $2-$1.

Podemos utilizar ?: para evitar que se memorize el contenido:

var myRegex = /1(?:23)+/gi;

Esto es todo por ahora. En otro tutorial veremos las funciones que tenemos disponibles para utilizar las expresiones regulares de varias formas en JavaScript.

Fuentes: MDN Regular Expressions

Regular expression enlightenment
Regexpal (regex tester)

jueves, 30 de mayo de 2013

Simular "text-overflow:ellipsis" para textos largos ( multilínea )

En CSS, si utilizamos las siguientes propiedades:
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
Podemos conseguir que un texto se corte a la anchura que queramos y se inserten automáticamente unos puntos suspensivos al final.



El problema es que sólo funciona para una única línea. El texto se corta cuando la línea sobrepasa la anchura del contenedor. Necesitamos incluir white-space: nowrap para evitar que el texto que no cabe se desplace a la línea siguiente.
Sería muy util poder hacer también algo como esto:



Es decir, tenemos un texto largo, de varias líneas ( sin white-space: nowrap ), y queremos que se corte mostrando "..." cuando supera la altura del contenedor.

Ellipsis multilínea con JavaScript

Sólo son necesarias unas líneas de JavaScript para conseguirlo. Supongamos que tenemos un texto largo en un div contenedor con una altura limitada:
<div id="container">
  <p>
  Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
  </p>
</div>

Tenemos el siguiente CSS para limitar la altura y anchura del contenedor y ocultar el texto que no cabe:
#container {
  width: 300px;
  height: 95px;
  overflow: hidden;
}
El texto quedaría cortado pero no tenemos ninguna indicación de ello:



Podemos solucionar el problema con unas lineas de JavaScript (y JQuery):
var containerHeight = $("#container").height();
var $text = $("#container p");

while ( $text.outerHeight() > containerHeight ) {
        $text.text(function (index, text) {
            return text.replace(/\W*\s(\S)*$/, '...');
       });
}
El resultado es:



Lo que hace este pequeño script es ir recortando palabras del final del texto hasta que la altura del texto es igual a la altura del contenedor.Toda la magia se realiza con la expresión regular:
text.replace(/\W*\s(\S)*$/, '...');
Básicamente esta instrucción sustituye la última palabra, junto con cualquier espacio en blanco que tenga delante, por "...". Esto se va repitiendo hasta que el texto encaja dentro del contenedor.

Creando una función genérica

Podemos hacerlo más flexible creando una función que incluya los "..." en cualquier texto largo que sobrepase el contenedor. Pasaremos como parámetro el id del div que contiene el texto.
La siguiente función es válida siempre que el marcado HTML sea como en el ejemplo anterior,el texto debe estar englobado en un <p></p> que está dentro del elemento que se pasa como parámetro. No es dificil cambiar la función para otra estructura.
function createEllipsis ( containerId ) {
    $container = $("#" + containerId);
    var containerHeight = $container.height();
    var $text = $container.find("p");

    while ( $text.outerHeight() > containerHeight ) {
        $text.text(function (index, text) {
            return text.replace(/\W*\s(\S)*$/, '...');
        });
    }
  }

Se utilizaría:
createEllipsis("container");

Hay tambien una solución para hacer algo parecido con CSS descrita en el post Multiline ellipsis in pure css pero tiene varios problemas. Necesita algún marcado extra en el HTML y, la más grave, si la línea en la que cortamos es corta (un punto y aparte), los puntos suspensivos quedan siempre pegados a la derecha y queda un hueco en blanco.

sábado, 25 de mayo de 2013

JavaScript: Cómo comprobar si un elemento existe en el DOM

Es muy común tener que comprobar si un elemento HTML existe en el documento que estamos manejando. Vamos a ver a continuación dos formas de hacerlo, una con JavaScript puro y la otra utilizando jQuery.

Vamos a suponer que el elemento en cuestión tiene una id que para nuestro ejemplo será elementID.

JavaScript puro

En JavaScript podemos utilizar document.getElementById:


if ( document.getElementById( "elementID" )) {
      //...
}

En realidad estamos intentando seleccionar el elemento con id="elementID". Si el elemento existe, document.getElementById() lo devuelve ( es un elemento del DOM y equivale a true ). Si no existe devuelve null que equivale a false.

Usando jQuery

En jQuery no nos basta con intentar simplemente seleccionar el elemento:


// esto no funciona!!
if ( $("#elementID") ) {
      //...
}

No funciona porque jQuery siempre devuelve un array de elementos, aunque sólo haya uno o incluso aunque no haya ninguno. Si el elemento no existe devolverá un array vacío, que equivale a true. Por lo tanto tenemos que comprobar el número de elementos devueltos:


if ( $("#elementID").length ) {
     //...
}

Cuando el array está vacio $("#elementID").length es 0 y por lo tanto false, para cualquier otro número será true.

miércoles, 22 de mayo de 2013

No abuses de las librerias externas

Las librerias externas como jQuery o underscore son una gran ayuda para desarrollar aplicaciones grandes. Son librerias de utilidades genericas y normalmente su uso es apropiado. El problema viene cuando algunos desarrolladores buscan una librería para cada elemento que tienen que desarrollar. He trabajado en algun proyecto en el que me he encontrado más de veinte plugins de jQuery como parte de una applicación.


Programación Frankenstein: crear una aplicación monstruosa a base de 'coser' librerías que hacen alguna cosita

Esto es la programación Frankenstein, crear una aplicación monstruosa a base de 'coser' librerías que hacen alguna cosita. Si mi aplicacion necesita un mosaico de fotos, busco un plugin que me lo haga. Si necesito un scroll personalizado busco un plugin, si necesito visualizar las fotos como un carrusel, busco un plugin, etc, etc.

No quiero decir que no utilicemos una librería o un plugin cuando se adapte perfectamente a nuestras necesidades o cuando proporcione una funcionalidad que tardaríamos meses en desarrollar, pero el abuso de códigos externos nos puede llevar a crear un monstruo inmantenible.

La mayoría de las veces lo que necesitamos es una versión muy reducida de lo que proporciona la librería, que tiene que ser flexible para soportar las necesidades de usuarios diferentes. Habrá cientos de líneas que no utilicemos y algunos errores sin solucionar que nos obligarán a modificar un código que no conocemos.

Los problemas principales son:

  • Tenemos en la aplicación miles de líneas de código que no conocemos
  • Tenemos, probablemente, miles de líneas de código que no usamos
  • Aparecerán errores que nos obligarán a rastrear y modificar estas librerias externas
  • El cliente, tarde o temprano, solicitará alguna funcionalidad/cambio que nos obligará a cambiar el código de las librerias
  • Una vez que cambiemos un código externo, la actualizacion de las librerias se convierte en una pesadilla. Tendremos que pasar todos los cambios a las nuevas versiones o bien estar atentos a los cambios que solucionan errores e incorporarlos en nuestra versión

Cedric Dugas publica en su blog una excelente entrada sobre este tema titulada Muerte a las librerías monolíticas en el que expone algunos problemas que ha encontrado con el abuso de librerias y propone hacerse las siguientes preguntas antes de incorporar código de terceros:

  • ¿Puedo programarlo yo fácilmente?
  • ¿Tengo tiempo para hacerlo?
  • ¿Que navegadores soporta esta librería?
  • ¿Cuantos errores sin resolver tiene ( open issues )?
  • ¿Que tamaño tiene?
  • ¿El autor es de confianza?

Me parece una buena check list para reflexionar un poco antes de 'crear un monstruo'.

Fuentes:

Death to monolithic libraries

lunes, 29 de abril de 2013

Strings multi-línea en Javascript

A veces es necesario asignar un texto largo, con varias líneas, a una variable. Si intentamos simplemente dividir el texto en varias líneas, fallará:
//Esta forma de hacerlo producirá un error
var myText = "Este es un texto muy largo que queremos 
              formatear en varias líneas. Un trozo de HTML 
              también sería un buen ejemplo de la necesidad 
              de asignar texto de varias líneas en una variable.";

Obtenemos el error:

SyntaxError: unterminated string literal

Hay dos formas muy comunes de hacerlo correctamente:
  1. Utilizando el código de escape ('\') antes del salto de línea
  2. Concatenando los strings de cada línea

Código de escape ('\') antes del salto de línea

El código sería.

var myText = "Este es un texto muy largo que queremos \
              formatear en varias líneas. Un trozo de HTML \
              también sería un buen ejemplo de la necesidad \
              de asignar texto de varias líneas en una variable.";


Esto funciona pero tiene algunos detractores porque no estaba en el estándar (en ECMAscript 5 sí se ha incluido) y porque los espacios en blanco después del código de escape pueden generar errores. Además algunos navegadores mantienen el salto de línea como parte del texto mientras otros lo eliminan ( en HTML esto no influye en el texto que veremos en pantalla).

En ECMAscript 3 no estaba permitido:
A LineTerminator character cannot appear in a string literal, even if preceded by a backslash '\'.
Pero en ECMAscript 5seccion 7.8.4:
"A line terminator character cannot appear in a string literal, except as part of a LineContinuation to produce the empty character sequence."
Lo que el estándar llama LineContinuation sería la secuencia de escape junto con el final de línea (salto de línea): '\' + <LineTerminator>.

Es importante tener en cuenta que los espacios en blanco que introducimos para indentar las líneas formarán parte del string. Normalmente no es un problema porque en HTML se mostrarán como un solo espacio, pero este comportamiento se puede modificar.

La guia de estilo de Google recomienda no utilizar esta técnica porque:
" Los espacios en blanco al principio de cada línea no podrán ser eliminados con seguridad en procesos de compilación; los espacios en blanco despues de la barra (escape) pueden producir errores difíciles de encontrar y, aunque la mayoría de los intérpretes lo soportan, no es parte de ECMAScript."
La última frase hemos visto que ya no tendría sentido, pero, en cualquier caso, Google recomienda utilizar strings concatenados como veremos a continuación.

Concatenando strings

El código sería:
var myText = "Este es un texto muy largo que queremos" +
              "formatear en varias líneas. Un trozo de HTML" +
              "también sería un buen ejemplo de la necesidad" +
              "de asignar texto de varias líneas en una variable.";


Esta es la solución estándar sin discusión. Funcionará perfectamente en todas las implementaciones de JavaScript porque es una simple concatenación de strings y evita los problemas con los espacios en blanco del método anterior. Evitamos también cualquier problema/diferencia que pueda surgir al minificar el código y eliminar los saltos de línea.

ECMAscript 6 tendrá strings multilínea

EcmaScript 6 introduce una notación nueva para soportar strings multilínea: las comillas hacia atrás.
var myText = `Say hello to 
  multi-line
  strings!`;


Fuentes:
StackOverflow: creating multiline strings in javascript
StackOverflow: add carriage returns to string for readability