Java Script
Java Script
Este capítulo analiza la gramática básica de JavaScript, declaraciones de variables, tipos de datos y literales.
Conceptos básicos
JavaScript está influenciado sobre todo por la sintaxis de Java, pero también de Awk, Perl y Python.
JavaScript es case-sensitive (distingue mayúsculas y minúsculas) y utiliza el conjunto de caracteres Unicode. Por ejemplo,
la palabra Früh (que significa "temprano" en Alemán) puede ser usada como el nombre de una variable.
Comentarios
La sintaxis de comentarios es la misma como en C++ y en muchos otros lenguajes:
// comentario en una sola línea
/* este es un comentario
multilínea
*/
Declaraciones
Hay tres tipos de declaraciones en JavaScript.
var
Declara una variable, inicializándola opcionalmente a un valor.
let
Declara una variable local en un bloque de ámbito, inicializándola opcionalmente a un valor.
const
Declara una constante de sólo lectura en un bloque de ámbito.
Variables
Las variables se usan como nombres simbólicos para valores en tu aplicación. Los nombres de las variables,
llamados identificadores, se rigen por ciertas reglas.
Un identificador en JavaScript tiene que empezar con una letra, un guión bajo (_) o un símbolo de dólar ($); los valores
subsiguientes pueden ser números. Debido a que JavaScript diferencia entre mayúsculas y minúsculas, las letras incluyen
tanto desde la "A" hasta la "Z" (mayúsculas) como de la "a" hasta la "z".
Puedes usar la ISO 8859-1 o letras Unicode tales como å y ü en un identificador. Puedes también usar el Unicode escape
sequences como caracteres en identificadores.
Algunos ejemplos de nombre permitidos son Numero_Visitas, temp99, _nombre, $nombre.
Declarando variables
Puedes declarar una variable de tres maneras:
Con la palabra clave var. Por ejemplo, var x = 42. Esta sintaxis puede ser usada para declarar tanto
variables locales como globales.
Simplemente asignándole un valor. Por ejemplo, x = 42. Esto siempre declara una variable global y no puede ser
cambiada a nivel local. Esto genera una advertencia strict de JavaScript. No deberías usar esta variante.
Con la palabra clave let. Por ejemplo, let y = 13. Esta variable puede ser usada para declarar una variable local en
un bloque de ámbito. Ver Ámbito de variable más abajo.
Evaluando variables
Una variable declarada usando la sentencia var o let sin asignarle un valor inicial tiene el valor undefined.
Al intentar acceder a una variable no declarada dará como resultado la excepción ReferenceError:
var a;
console.log('El valor de a es ' + a); // El valor de a es undefined
let x;
console.log('El valor de x es ' + x); // El valor de x es undefined
var input;
if(input === undefined){
hazEsto();
} else {
hazEso();
}
El valor undefined se comporta como un false cuando se utiliza en un contexto booleano. Por ejemplo, el siguiente código
ejecuta la función myFunction porque el elemento myArray no ha sido definido:
var a;
a + 2; // Se evalua a NaN
Cuando se evalúa una variable nula, el valor null se comporta como el 0 en operaciones aritméticas y como false en
operaciones lógicas. Por ejemplo:
var n = null;
console.log(n * 32); // Va a lanzar 0 a la consola
Ámbito de variable
Cuando declaras una variable fuera de una función, se le denomina variable global, porque está disponible para cualquier
otro código en el documento actual. Cuando declaras una variable dentro de una función, se le denomina variable local,
porque está disponible solo dentro de esa función donde fué creada.
Antes de ECMAScript 6 Javascript no tiene ámbito de sentencias de bloque; más bien, una variable declarada dentro
de un bloque es local para la función (o ámbito global) en la que reside el bloque. Por ejemplo, el siguiente código
registrará 5, porque el ámbito de x es la función (o contexto global) dentro del cual se declara x, no el bloque, que en este
caso es la sentencia if.
if (true) {
var x = 5;
}
console.log(x); // x vale 5
if (true) {
let y = 5;
}
console.log(y); // ReferenceError: y no está definida
Variable hoisting
Otra cosa inusual acerca de las variables en JavaScript es que pueden hacer referencia a una variable declarada más
tarde, sin obtener una excepción. Este concepto se conoce como hoisting; Las variables en JavaScript son en cierto
sentido "elevadas" a la parte superior de la función o declaración. Sin embargo, las variables que no se han inicializado
todavía devolverán un valor undefined.
/**
* Ejemplo 1
*/
console.log(x === undefined); // true
var x = 3;
/**
* Ejemplo 2
*/
// devolverá un valor undefined
var myvar = "my value";
(function() {
console.log(myvar); // undefined
var myvar = "local value";
})();
/**
* Ejemplo 1
*/
var x;
console.log(x === undefined); // true
x = 3;
/**
* Ejemplo 2
*/
var myvar = "my value";
(function() {
var myvar;
console.log(myvar); // undefined
myvar = "local value";
})();
Debido al hoisting, todas las declaraciones var en una función deben colocarse lo más cerca posible de la parte superior
de la función. Esta buena práctica mejora la claridad del código.
En ECMAScript 2015, let (const) no elevará la variable a la parte superior del bloque. Sin embargo, hacer referencia a la
variable en el bloque antes de la declaración de la variable resulta en un ReferenceError. La variable se encuentra en una
"zona muerta temporal" desde el inicio del bloque hasta que se procesa la declaración.
console.log(x); // ReferenceError
let x = 3;
Función hoisting
Para las funciones, solo la declaración de la función se eleva a la parte superior y no la expresión de la función.
/* Declaración de la función */
foo(); // "bar"
function foo() {
console.log("bar");
}
/* Expresión de la función */
Variables Globales
Las variables globales son, de hecho, propiedades del objeto global. En las páginas web, el objeto global es window, el
cual puede establecer y acceder a las variables globales usando la sintaxis window.variable.
Por lo tanto, puedes acceder a variables globales declaradas en una ventana o frame de otra ventana o frame
especificando el nombre de la ventana o frame. Por ejemplo, si una variable denominada phoneNumber es declarada en un
documento, puede consultar a esta variable desde un iframe como parent.phoneNumber.
Constantes
Puede crear una de solo lectura, llamada constante con la palabra clave const. La sintaxis del identificador de la constante
es el mismo como para un indentificador de variable: debe de empezar con una letra, guión bajo(_) o símbolo de dollar($) y
puede contener alfabéticos, numéricos o guiones bajos.
const PI = 3.14;
Una constante no puede cambiar de valor mediante la asignación o volver a declararse mientras se ejecuta el script.
Las reglas de ámbito para las constantes son las mismas que las de las variables let en un ámbito de bloque. Si la palabra
clave const es omitida, el identificador se asume que representa una variable.
No puedes declarar una constante con el mismo nombre que una función o una variable en el mismo ámbito. Por ejemplo:
//sentencias
}
Nota: Las propiedades de los objetos asignados a constantes no son protegidos, es por esto que la siguiente sentencia
se ejecuta sin problemas.
Nota: El contenido de los array tampoco está protegido cuando es asignado a una constante, es por esto que la siguiente
sentencia se ejecuta sin problemas.
JavaScript es un lenguaje de tipo dinámico. Esto significa que no tienes que especificar el tipo de dato de una variable
cuando la declaras, y los tipos de datos son convertidos automáticamente de acuerdo a lo que se necesite en la ejecución
del script. Así, por ejemplo, puedes definir una variable de la siguiente manera:
Y luego, puedes asignarle una cadena a esa misma variable, por ejemplo:
Debido a que es un lenguaje de tipos dinámicos, esta asignación no causa un mensaje de error.
En expresiones que involucran valores numéricos y de string con el operador +, JavaScript convierte valores numéricos a
string. Por ejemplo, considera las siguientes declaraciones:
x = "La respuesta es " + 42 // "La respuesta es 42"
y = 42 + " es la respuesta" // "42 es la respuesta"
En declaraciones que involucran otros operadores, JavaScript no convierte los valores numéricos a string. Por ejemplo:
"37" - 7 // 30
"37" + 7 // "377"
parseInt() y parseFloat()
parseInt()
parseFloat()
parseInt sólo retornará números enteros, por lo que su uso es disminuido por los decimales. Adicionalmente, una buena
práctica para parseInt es incluir siempre el parámetro radix. El parámetro rádix es usado para especificar qué sistema
numérico será usado.
Un método alternativo para recibir un número de un string es con el operador + (más unario):
Literales
Los literales se utilizan para representar valores en JavaScript. Estos son valores fijos, no variables, que literalmente
proporciona en su script. Esta sección describe los siguientes tipos de literales:
Literales Array
Literales Boolean
Literales de punto Flotante
Literales Enteros
Literales Tipo Objeto
Literales String
Literales Array
Un literal array es un lista de cero o más expresiones, cada uno representa un elemento array, entre corchetes ([]). Cuando
crea un array usando un literal array, se inicializa con los valores especificados como sus elementos, y su longitud se
establece por el número de argumentos especificados.
El siguiente ejemplo crea el array cafes con tres elementos y una longitud de tres:
Si un array se crea usando un literal en un script de nivel superior, JavaScript interpreta el array cada vez que se evalúa la
expresión que contiene el literal array. Además, un literal usado en una función se crea cada vez que es llamada la
función.
Los literales array son también objetos array. Consulte Array y colecciones indexadas para los detalles sobre
objetos Array.
No tienes que especificar todos los elementos en un literal array. Si pones dos comas en una fila, se crea el array
con undefined para los elementos no especificados. El siguiente ejemplo crea el array peces:
var peces = ["Leon", , "Angel"];
Este array tiene dos elementos con valores y un elemento vacío (peces[0] es "Leon", peces[1] es undefined, y peces[2] es
"Angel").
Si incluyes una coma al final de la lista de los elementos, la coma es ignorada. En el siguiente ejemplo, la longitud del array
es tres. No hay miLista[3]. Todas las demás comas en la lista indican un nuevo elemento. (Nota: Las comas finales
pueden crear errores en las versiones anteriores del navegador y es una buena practica eliminarlos.)
En el siguiente ejemplo, la longitud del array es cuatro, y miLista[0] y miLista[2] faltan.
En la siguiente ejemplo, la longitud del array es cuatro, y miLista[1] y miLista[3] faltan. Solo la última coma es ignorada.
Comprender el comportamiento de las comas adicionales es importante para comprender JavaScript como un lenguaje,
sin embargo cuando escribimos nuestro propio código: declaramos explícitamente los elementos que faltan
como undefined esto aumentará la claridad y el mantenimiento de su código.
Literales Booleanos
Los literales de tipo Booleanos tienen 2 valores posibles: true y false.
NO confundir los valores primitivos Booleanos true y false con los valores true y false del Objeto Booleano. El objeto
Booleano es un contenedor alrededor del tipo de dato Primitivo Booleano. Para más información revisa Booleano .
Literales Enteros
Los Enteros pueden ser expresados en decimal (base 10), hexadecimal (base 16), octal (base 8) y binario (base 2).
El Literal entero decimal consiste en una secuencia de dígitos sin un prefijo 0 (cero).
El prefijo 0 (cero ) en un literal entero indica que está en octal. Los enteros octales pueden incluir sólo los dígitos 0-
7.
El tipo 0x (or 0X) indica hexadecimal. Los enteros Hexadecimal pueden incluir dígitos del (0-9) y letras a-f y A-F.
Algunos ejemplos de enteros Literales son:
Para mas Información, revisa la Referencia de literales Numéricos en la Léxica Gramática.
Literales de Punto Flotante
Un Literal de punto flotante, puede tener las siguientes partes:
[(+|-)][digitos][.digitos][(E|e)[(+|-)]digitos]
Por ejemplo:
3.14
2345.789
.3333333333333333333
-.283185307179586
Literales Tipo Objeto
Un literal Objeto es una lista de cero o mas parejas de nombres de propiedades asociadas con el respectivo valor,
encerradas entre corchetes ({}). No debes usar un objetos literal al comienzo de una sentencia. Esto dará lugar a un error
o no se comportará como se espera, porque los corchetes { serán interpretados como el inicio de un bloque.
El siguiente es un ejemplo de un objeto literal. El primer elemento del objeto carro define una propiedad, miCarro, y asigna
a este el String , "Saturn"; el segundo elemento, a la propiedad getCarro, se le asigna inmediatamente el resultado de
invocar a la función (TiposCarro("Honda")); el tercer elemento, la propiedad especial, usa una variable existente (Ventas).
var Ventas = "Toyota";
function TiposCarro(nombre) {
if (nombre== "Honda") {
return nombre;
} else {
return "Lo siento, nosotros no vendemos " + nombre + ".";
}
}
console.log(carro.miCarro); // Saturn
console.log(carro.getCarro); // Honda
console.log(carro.especial); // Toyota
Adicionalmente el nombre de una propiedad puede ser un literal entero o puede corresponder a otro objeto, como se
muestra a continuación.
console.log(auto.algunosAutos.b); // Jeep
console.log(auto[7]); // Mazda
Los nombres de las propiedades de un objeto pueden ser cualquier string, incluyendo un string vacio. si el nombre de la
propiedad no es un identificador JavaScript valido, este debe ser encerrado en barras cuadradas. Los nombres de
propiedad que no son identificadores validos, no pueden ser accedidos con la propiedad punto (.), pero pueden ser
accedidos y seteados con la notacion de un arreglo ("[]").
var propiedadesDeNombreInusual = {
"": "Un string vacio",
"!": "Bang!"
}
console.log(propiedadesDeNombreInusual .""); // SyntaxError: Unexpected string
console.log(propiedadesDeNombreInusual [""]); // "Un string vacio"
console.log(propiedadesDeNombreInusual .!); // SyntaxError: Unexpected token !
console.log(propiedadesDeNombreInusual ["!"]); // "Bang!"
Ten en cuenta:
RegExp literales
Un regex literal (El cual será definido en detalle despues) es un patron encerrado entre barras diagonales. El siguiente es
un ejemplo de regex literal.
var re = /ab+c/;
Literales String
Un literal String corresponde a Cero o mas caracteres, encerrados dentro de comillas dobles (") o sencilla (') . Un string
debe estar delimitado por comillas del mismo tipo; esto quiere decir que, siempre ambas son dobles o sencillas en cada
uno de los casos. Los siguientes son ejemplos de literales String:
"foo"
'bar'
"1234"
"Una linea \n otra linea"
"El gato de Jhon"
Puedes utilizar cualquiera de los métodos del objeto String en un literal de tipo string—JavaScript automáticamente
convierte el literal string en un objeto String de manera temporal, llama al método, y finalmente destruye el objeto temporal
de tipo String. También puedes usar la propiedad String.length con un literal string:
Se recomienda que uses un literal string a menos que sea específicamente necesario el uso de un objeto de tipo String.
Mira String para detalles acerca de objetos String .
Adicional a los caracteres normales, también puede incluir caracteres especiales en los strings, como se muestra en el
siguiente ejemplo:
\XXX
Los caracteres con la codificación Latin-1 especificada por tres dígitos octales XXX entre 0 y 377. Por ejemplo, \251 es la
secuencia octal para el símbolo copyright.
\xXX
Los caracteres con la codificación Latin-1 especificada por dos dígitos hexadecimales XX entre 00 y FF. Por ejemplo, \xA9
es la secuencia hexadecimal para el símbolo copyright.
\uXXXX
Los caracteres Unicode especificados por la secuencia de cuatro dígitos Hexadecimales XXXX. Por ejemplo, \u00A9 es la
secuencia Unicode para el símbolo copyright . Ver Secuencias de escape Unicode .
Caracteres de Escape
Para caracteres no listados en la Tabla 2.1, la precedencia del backslash es ignorada, pero su uso esta obsoleto y debe
ser evitado.
Puedes insertar comillas dobles dentro de un string anteponiendo un carácter backslash. significa esto como un escape de
las comillas. Por ejemplo:
var quote = "El lee \"La cremación de Sam McGee\" de R.W. Service.";
console.log(quote);
El resultado de esto sería:
Para incluir un literal backslash en un string, debes usar el caracter de escape backslash. Por ejemplo, para asignar la
ruta c:\temp a un string, use lo siguiente:
También puedes insertar saltos de línea. El backslash y el salto de línea son removidos del valor del string.
Aunque JavaScript no tiene sintaxis "heredoc" puede acercarse insertando un backslash y un salto de linea al final de cada
linea:
var poem =
"Roses are red,\n\
Violets are blue.\n\
I'm schizophrenic,\n\
And so am I."
Control de flujo y manejo de errores
Javascript soporta un conjunto compacto de sentencias, específicamente para el manejo de flujo, que puedes usar para
incorporar mayor interactividad a tus aplicaciones. Este capítulo provee una vista general de las mismas.
La guía de referencia de Javascript contiene detalles exhaustivos sobre las sentencias mencionadas en este capítulo. El
punto y coma (;) se utiliza para separar sentencias en código Javascript.
Cualquier expresión en Javascript también es una sentencia. Puedes ver Expresiones y operadores para más información
sobre expresiones.
Sentencia de bloque
La sentencia de bloque es el tipo de sentencia más básico y se utiliza para agrupar sentencias. El bloque se delimita entre
un par de llaves:
sentencia_1;
sentencia_2;
.
.
.
sentencia_n;
Ejemplo
Los bloques de sentencias son comúnmente utilizados para sentencias de control de flujo (ej. if, for, while).
var x = 1;
{
var x = 2;
}
console.log(x); // imprime 2
Este código imprime el número 2 dado que la sentencia var x dentro del bloque está en el mismo ámbito que la
sentencia var x definida antes del bloque. En C o Java el equivalente de este código imprimiría 1.
A partir de ECMAScript 6, se introduce el ámbito a nivel bloque utilizando let para declarar las variables. Ver la
referencia let para más información.
Sentencias condicionales
Una sentencia condicional es un conjunto de comandos que se ejecutan si una condición es verdadera. JavaScript soporta
dos sentencias condicionales: if...else y switch
Sentencia if...else
Se utiliza la sentencia if para comprobar si la condición lógica es verdadera. Se utiliza la opción else para ejecutar un
sentencia si la condición es falsa. A continuación se muestra un ejemplo de if...else:
if (condición) {
sentencia_1;
} else {
sentencia_2;
Aquí la condición puede ser cualquier expresión que se evalúa a true o false. Consultar Boolean para una explicación de
como se evalúa true y false. Si la condición es verdadera, se ejecuta sentencia_1; de lo contrario, se
ejecuta sentencia_2. La sentencia_1 y la sentencia_2 pueden ser cualquier sentencia, incluyendo otras sentencias anidadas
en if.
También puedes componer sentencias más complejas usando else if para tener múltiples condiciones, como se muestra
a continuación:
if (condición_1) {
sentencia_1;
} else if (condición_2) {
sentencia_2;
} else if (condición_n) {
sentencia_n;
} else {
ultima_sentencia;
}
En el caso de condiciones múltiples solamente la primera condición lógica que evalúa a verdadero va a ser ejecutada.
Para ejecutar múltiples sentencias, agruparlas dentro de sentencias de bloque ({ ... }) . En general, usar siempre
sentencias de bloque es una buena práctica, sobre todo cuando se anidan sentencias if:
if (condición) {
ejecutar_sentencia_1_si_condición_es_verdadera;
ejecutar_sentencia_2_si_condición_es_verdadera;
} else {
ejecutar_sentencia_3_si_condición_es_falsa;
ejecutar_sentencia_4_si_condición_es_falsa;
Es aconsejable no usar asignación simple dentro de una expresión condicional porque dicha asignación puede ser
confundida con el comparador de igualdad cuando se lee de pasada el código. Por ejemplo, no usar el siguiente código:
if (x = y) {
/* sentencias aquí */
}
Si necesitas usar una asignación dentro de una expresión de condición, una práctica común es poner paréntesis
adicionales alrededor de la asignación. Por ejemplo:
if ((x = y)) {
/* sentencias aquí */
}
Valores falsos:
No confundir los valores primitivos booleanos true y false con los valores true y false del objeto Boolean. Por ejemplo:
Ejemplo
En el siguiente ejemplo, la función comprobarDatos devuelve true si el número de caracteres en un objeto Text es tres; en
otro caso, muestra una alerta y devuelve false.
function comprobarDatos() {
if (document.form1.threeChar.value.length == 3) {
return true;
} else {
alert("Introduce exactamente tres caracteres. " +
document.form1.threeChar.value + " no es válido.");
return false;
}
}
switch
Una sentencia switch permite a un programa evaluar una expresión e intentar igualar el valor de dicha expresión a una
etiqueta de caso (case). Si se encuentra una coincidencia, el programa ejecuta la sentencia asociada. Una
sentencia switch se describe como se muestra a continuación:
switch (expresión) {
case etiqueta_1:
sentencias_1
[break;]
case etiqueta_2:
sentencias_2
[break;]
...
default:
sentencias_por_defecto
[break;]
El programa primero busca una claúsula case con una etiqueta que coincida con el valor de la expresión y, entonces,
transfiere el control a esa cláusula, ejecutando las sentencias asociadas a ella. Si no se encuentran etiquetas coincidentes,
el programa busca la cláusula opcional default y, si se encuentra, transfiere el control a esa cláusula, ejecutando las
sentencias asociadas. Si no se encuentra la cláusula default, el programa continúa su ejecución por la siguiente sentencia
al final del switch. Por convención, la cláusula por defecto es la última cláusula, aunque no es necesario que sea así.
La sentencia opcional break asociada con cada cláusula case asegura que el programa finaliza la sentencia switch una vez
que la sentencia asociada a la etiqueta coincidente es ejecutada y continúa la ejecución por las sentencias siguientes a la
sentencia switch. Si se omite la sentencia break, el programa continúa su ejecución por la siguiente sentencia que haya en
la sentencia switch.
Ejemplo
En el siguiente ejemplo, si tipoFruta se evalúa como "Plátanos", el programa iguala el valor con el caso "Plátanos" y
ejecuta las sentencias asociadas. Cuando se encuentra la sentencia break, el programa termina el switch y ejecuta las
sentencias que le siguen. Si la sentencia break fuese omitida, la sentencia para el caso "Cerezas" también sería ejecutada.
switch (tipoFruta) {
case "Naranjas":
console.log("Naranjas cuestan 0,59€ el kilo.");
break;
case "Manzanas":
console.log("Manzanas cuestan 0,32€ el kilo.");
break;
case "Plátanos":
console.log("Plátanos cuestan 0,48€ el kilo.");
break;
case "Cerezas":
console.log("Cerezas cuestan 3,00€ el kilo.");
break;
case "Mangos":
console.log("Mangos cuestan 0,56€ el kilo.");
break;
case "Papayas":
console.log("Mangos y papayas cuestan 2,79€ el kilo.");
break;
default:
console.log("Disculpa, no tenemos el tipo de fruta " + tipoFruta + ".");
}
console.log("¿Te gustaría tomar algo?");
Excepciones ECMAScript
DOMException and DOMError
Sentencia throw
Utiliza la sentencia throw para lanzar una excepción. Cuando lanzas un excepción, se especifica la expresión que contiene
el valor para ser lanzado:
throw expresión;
Puedes lanzar cualquier expresión, no solo expresiones de un tipo especifico. En el siguente código lanzamos varias
excepciones de varios tipos:
Note: Puedes especificar un objeto cuando lanzas una excepción. A continuación, puedes hacer referencia a las propiedades
del objeto en un bloque catch.
El bloque catch
Un bloque catch es usado para manejar todas las excepciones que pueden ser generadas en el bloque try.
catch (catchID) {
instrucciones
}
El bloque catch especifica un identificador (catchID en la sintaxis anterior) que tiene el valor especificado por la
sentencia throw; puedes usar este identificador para obtener información acerca de la excepción que fue arrojada.
JavaScript crea este identificador cuando ha entrado en el bloque catch; el identificador dura mientras dure el bloque catch;
después de que el bloque catch termine su ejecución, el identificador ya no estará disponible.
Por ejemplo, el siguiente código arroja una excepción. Cuando la excepción ocurre, el control es transferido al
bloque catch.
try {
throw "myException" // genera una excepción
}
catch (e) {
// instrucciones para manejar cualquier excepción generada
logMyErrors(e) // Pasa el objeto de excepción a un manejador de errores
}
El bloque finally
El bloque finally contiene instrucciones para ejecutar luego de la ejecución del bloque try y el bloque catch pero antes de
las instrucciones ubicadas luego de la sentencia try...catch. El bloque finally se ejecuta cuando se haya arrojado o no
una excepción. Si una excepción es arrojada, las instrucciones en el bloque finally se ejecutan incluso si no existe un
bloque catch que maneje la excepción.
Se puede usar el bloque finally para hacer que tu script falle con gracia cuando una excepción ocurre; por ejemplo,
puedes tener la necesidad de liberar un recurso que tu script tiene ocupado. El siguiente ejemplo abre un archivo y luego
ejecuta instrucciones que usan el archivo (JavaScript del lado del servidor permite acceder a archivos). Si una excepción
es arrojada mientras el archivo está abierto, el bloque finally cierra el archivo antes de que el script falle.
openMyFile();
try {
writeMyFile(theData); // Esto puede arrojar un error
} catch(e) {
handleError(e); // Si ocurre un error es manejado
} finally {
closeMyFile(); // Siempre cierra el recurso
}
function f() {
try {
console.log(0);
throw "bogus";
} catch(e) {
console.log(1);
return true; // Esta sentencia de retorno es suspendida
// hasta que el bloque finally esté completo
console.log(2); // no alcanzable
} finally {
console.log(3);
return false; // sobreescribe la sentencia de retorno anterior
console.log(4); // no alcanzable
}
// "return false" es ejecutada ahora
console.log(5); // no alcanzable
}
f(); // console 0, 1, 3; retorna false
Sobreescribiendo los valores retornados por el bloque finally también aplica a excepciones arrojadas o relanzadas dentro
de un bloque catch:
function f() {
try {
throw "bogus";
} catch(e) {
console.log('caught inner "bogus"');
throw e; // Esta sentencia throw es suspendida hasta que
// el bloque finally se termine de ejecutar
} finally {
return false; // Sobreescribe la sentencia throw anterior
}
// "return false" es ejecutado ahora
}
try {
f();
} catch(e) {
// Esta nunca es encontrada porque la sentencia throw dentro
// del bloque catch es sobrescrita por la sentencia return
// en el bloque finally
console.log('caught outer "bogus"');
}
// SALIDA
// atrapado dentro de "bogus"
Sentencias try...catch anidadas
Es posible anidar una o más sentencias try...catch. Si una sentencia try...catch interna no posee un bloque catch, la
sentencia try...catch exterior verifica si el bloque exterior genera una coincidencia.
Utilizando objetos de Error
Dependiendo del tipo de error, es posible usar el 'name' (nombre) y el 'message' (mensaje) propiedades para obtener un
mensaje más refinado. La propiedad 'name' provee la clase general del Error(por ejemplo, 'DOMException' or 'Error'),
mientras que la propiedad 'message' por lo general provee un breve mensaje que puede ser obtenido convirtiendo el error
de object a string.
Si estás arrojando tus propias excepciones, en orden para tomar ventaja de estas propiedades (Como si tu bloque catch
no discrimina entre tus propias excepciones y las excepciones del sistema), puedes usar el constructor de Error. Por
ejemplo:
function doSomethingErrorProne () {
if (ourCodeMakesAMistake()) {
throw (new Error('The message'));
} else {
doSomethingToGetAJavascriptError();
}
}
....
try {
doSomethingErrorProne();
}
catch (e) {
console.log(e.name); // muestra 'Error'
console.log(e.message); // muestra 'The message' o un error de JavaScript)
}
Promesas
A partir de ECMAScript 6, Javascript gana soporte para los objetos Promise que le permiten controlar el flujo de
operaciones diferidas y asíncronas.
Un objeto Promise puede estar ubicado en estos estados:
pending: Estado inicial, no terminada exitosamente o rechazada.
fulfilled: operación exitosa.
rejected: operación fallida.
settled: la Promesa ha sido exitosa o fallida, pero no está pendiente.
Cargando una imagen con XHR
Un simple ejemplo del uso de Promise y XMLHttpRequest es cargar una imagen que está disponible en el
repositorio promise-test de MDN GitHub. Puedes verlo también en acción. Cada paso es comentado y permite que sigas la
arquitectura de la Promesa y XHR de cerca. Aquí está una versión sin comentar, mostrando el flujo de un Promise para que
puedas tener una idea:
function imgLoad(url) {
return new Promise(function(resolve, reject) {
var request = new XMLHttpRequest();
request.open('GET', url);
request.responseType = 'blob';
request.onload = function() {
if (request.status === 200) {
resolve(request.response);
} else {
reject(Error('Image didn\'t load successfully; error code:'
+ request.statusText));
}
};
request.onerror = function() {
reject(Error('There was a network error.'));
};
request.send();
});
}
Bucles e iteración
Puedes pensar en un bucle como una versión "computarizada" de un juego en el que pides a alguien dar X pasos en una
dirección y luego Y (pasos) en otra; por ejemplo, la orden "Da cinco pasos hacia el Este" podría expresarse de la siguiente
forma como bucle:
var paso;
for (paso = 0; paso < 5; paso++) {
// Se ejecuta 5 veces, con valores desde paso desde 0 hasta 4.
console.log('Dando un paso al Este');
};
Hay muchas clases diferentes de bucles, pero todos ellos hacen en esencia lo mismo: repetir una acción un numero de
veces (y de hecho es posible que este número sea cero). Los diferentes bucles ofrecen también diferentes formas de
determinar sus puntos de inicio y final. Hay determinadas situaciones que se resuelven más fácilmente con un tipo de
bucles que otros.
sentencia for
sentencia do...while
sentencia while
sentencia label
sentencia break
sentencia continue
sentencia for...in
sentencia for...of
sentencia for
Un bucle for se repite hasta que la condición especificada se evalúa como false. El bucle for en JavaScript es similar al
de Java y C. Una sentencia for se muestra como sigue:
sentencia
<form name="selectForm">
<p>
<label for="musicTypes">Choose some music types, then click the button below:</label>
<select id="musicTypes" name="musicTypes" multiple="multiple">
<option selected="selected">R&B</option>
<option>Jazz</option>
<option>Blues</option>
<option>New Age</option>
<option>Classical</option>
<option>Opera</option>
</select>
</p>
<p><input id="btn" type="button" value="How many are selected?" /></p>
</form>
<script>
function howMany(selectObject) {
var numberSelected = 0;
for (var i = 0; i < selectObject.options.length; i++) {
if (selectObject.options[i].selected) {
numberSelected++;
}
}
return numberSelected;
}
sentencia do...while
La sentencia do...while se repite hasta que la condición especificada que se evalúa sea false. Una sentencia do...while se
mostrará como sigue:
do
sentencia
while (condicion);
sentencia se ejecuta antes de que la condición sea evaluada. Para ejecutar múltiplessentencias, use un bloque de
sentencias ({ ... }) para agruparlas. Si condicion es true, la sentencia se ejecuta de
nuevo. Al final de cada ejecución, la
condición es comprobada. Cuando la condición es falsa, la ejecución se detiene y el control pasa a la sentencia
siguiente al do...while.
Ejemplo
En el siguiente ejemplo, el bucle do itera al menos una vez y vuelve a hacerlo mientras i sea menor que 5.
do {
i += 1;
console.log(i);
} while (i < 5);
sentencia while
Una sentencia while ejecuta sus sentencias mientras la condición sea evaluada como verdadera. Una
sentencia while tiene el siguiente aspecto:
while (condicion)
sentencia
Si la condición cambia a falsa, la sentencia dentro del bucle deja de ejecutarse y el control pasa a la sentencia
inmediatamente después del bucle.
La condición se evalúa antes de que la sentencia contenida en el bucle sea ejecutada. Si la condición devuelve verdadero,
la sentencia se ejecuta y la condición se comprueba de nuevo. Si la condición es evaluada como falsa, se detiene
la ejecución y el control pasa a la sentencia siguiente al while.
Para ejecutar múltiples sentencias, use un bloque de sentencias ({ ... }) para agruparlas.
Ejemplo 1
El siguiente bucle while itera mientras n sea menor que tres:
n = 0;
x = 0;
while (n < 3) {
n++;
x += n;
}
Con cada iteración, el bucle incrementa n y añade ese valor a x. Por consiguiente, x y ntoman los siguientes valores:
Después del primer paso: n = 1 y x = 1
Después del segundo paso: n = 2 y x = 3
Después del tercer paso: n = 3 y x = 6
Tras completar el tercer paso, la condición n < 3 ya no es verdadera, por tanto el bucle termina.
Ejemplo 2
Evite los bucles infinitos. Asegúrese de que la condición en un bucle llegue finalmente a ser falsa; de otra forma, el bucle
nunca terminará. Las sentencias en el siguiente bucle while se ejecutan sin fin, porque la condición nunca llega a ser falsa:
while (true) {
console.log("Hello, world");
}
sentencia label
Un label proporciona una sentencia con un identificador que permite referirse a él desde cualquier lugar de su
programa. Por ejemplo, usted puede usar un label para identificar un bucle, y usar las sentencias break o continue para
indicar si el programa debe interrumpir un bucle o continuar su ejecución.
La sintaxis de la sentencia label es:
label :
sentencia
El valor de label puede ser cualquier identificador JavaScript que no sea una palabra reservada. La sentencia que usted
identifique con un label podrá ser cualquier sentencia.
Ejemplo
En este ejemplo, el label markLoop identifica a un bucle while.
markLoop:
while (theMark == true) {
doSomething();
}
sentencia break
Use la sentencia break para salir de un bucle, switch, o en conjunto con una sentencia label.
Cuando use break sin un label, finaliza inmediatamente el código encerrado en while, do-while, for, o switch y
transfiere el control a la siguiente sentencia.
Cuando usted use break con un label, termina la sentencia especificada por label.
La sintaxis de la sentencia break es la siguiente:
1. break;
2. break label;
La primera forma de la sintaxis finaliza con lo encerrado por el bucle o switch; la segunda finaliza lo especificado por la
sentencia label.
Ejemplo 1
El siguiente ejemplo itera a través de los elementos en un array hasta que encuentra que un índice de un elemento cuyo
valor es elValor:
Ejemplo 2: Breaking a un label
var x = 0;
var z = 0
labelCancelLoops: while (true) {
console.log("Outer loops: " + x);
x += 1;
z = 1;
while (true) {
console.log("Inner loops: " + z);
z += 1;
if (z === 10 && x === 10) {
break labelCancelLoops;
} else if (z === 10) {
break;
}
}
}
sentencia continue
La sentencia continue puede usarse para reiniciar una sentencia while, do-while, for, o label.
Cuando use continue sin un label, este termina la iteración en curso del código encerrado en una
sentencia while, do-while, o for y continúa la ejecución del bucle con la siguiente iteración. A diferencia de la
sentencia break, continueno termina completamente la ejecución del bucle. En un bucle while, salta atrás hasta la
condición. En un bucle for, salta a la expresionIncremento.
Cuando use continue con un label, esta se aplica al bucle identificado con el label indicado.
La sintaxis de la sentencia continue es la siguiente:
1. continue;
2. continue label;
Ejemplo 1
El siguiente ejemplo muestra un bucle while con una sentencia continue que se ejecuta cuando el valor de i es tres.
Así, n toma los valores uno, tres, siete, y doce.
i = 0;
n = 0;
while (i < 5) {
i++;
if (i == 3) {
continue;
}
n += i;
}
Ejemplo 2
Una sentencia etiquetada checkiandj contiene una sentencia etiquetada checkj. Si se encuentra continue, el programa
termina la iteración en curso de checkj y empieza la siguiente iteración. Cada vez que continue es
encontrado, checkj reitera hasta que su condición devuelve false. Y cuando devuelve false, el resto de la
sentencia checkiandj es completada, y checkiandj reitera hasta que su condición devuelve false. Cuando esto ocurre
el programa continua en la siguiente sentencia después de checkiandj.
Si continue tenía una etiqueta checkiandj, el programa continuaría al principio de la sentencia checkiandj.
checkiandj:
while (i < 4) {
console.log(i);
i += 1;
checkj:
while (j > 4) {
console.log(j);
j -= 1;
if ((j % 2) == 0) {
continue checkj;
}
console.log(j + " is odd.");
}
console.log("i = " + i);
console.log("j = " + j);
}
sentencia for...in
La sentencia for...in itera una variable especificada sobre todas las propiedades enumerables de un objeto. Para cada
propiedad distinta, JavaScript ejecuta las sentencias especificadas. Una sentencia for...in será como sigue:
sentencias
Ejemplo
La siguiente función toma como su argumento un objeto y el nombre del objeto. Entonces itera sobre todas las
propiedades del objeto y devuelve una cadena que lista los nombres de las propiedades y sus nombres.
coche.marca = Ford
coche.modelo = Mustang
Arrays
Aunque puede ser tentador usar esto como una forma de iterar sobre elementos Array, la sentencia for...in devolverá el
nombre de las propiedades que usted ha definido además de los índices numéricos. En consecuencia es mejor usar un
bucle for tradicional con un índice numérico cuando esté iterando sobre arrays, ya que la sentencia for...in itera sobre las
propiedades definidas por el usuario además de los elementos del array, si usted modifica el objeto Array, por ejemplo
añadiendo propiedades personalizadas o métodos.
sentencia for...of
La sentencia for...of crea un bucle iterando sobre objetos iterables (incluyendo Array, Map, Set, argumentos, objetos etc),
invocando una iteración personalizada conectando con sentencias para ser ejecutadas por el valor de cada propiedad
distinta.
Expresiones y operadores
Operadores
JavaScript tiene los siguientes tipos de operadores. Esta sección describe dichos operadores y contiene información
sobre el orden de los mismos:
Operadores de asignación
Operadores de comparación
Operadores aritméticos
Operadores bit a bit
Operadores lógicos
Operadores de cadena de caracteres
Operador condicional (ternario)
Operador coma
Operadores unarios
Operadores relacionales
JavaScript tiene operadores binarios y unarios, y un operador ternario especial, el operador condicional. Un
operador binario requiere dos operandos, uno antes del operador y otro después de este.
Por ejemplo, 3+4 o x*y.
Un operador unario requiere solamente un operando, ya sea antes o después del operador:
operando operador
operador operando
Por ejemplo, x++ o ++x
Operadores de asignación
Un operador de asignación asigna un valor al operando de la izquierda en función del valor del operando de la derecha. El
operador básico de asignación es el de igual (=), que asigna el valor del operando de la derecha al operando de la
izquierda. Por ejemplo, x = y, está asignando el valor de y a x.
También existen operadores compuestos de asignación que son la forma abreviada de las operaciones de la siguiente
tabla:
Asignación de adición x += y x = x + y
Asignación de sustracción x -= y x = x - y
Asignación de multiplicación x *= y x = x * y
Asignación de división x /= y x = x / y
Asignación de resto x %= y x = x % y
Asignación OR binaria x |= y x = x | y
Destructuración
Para asignaciones mas complejas, la sintaxis de asignación con destructuración es una expresión de Javascript que
permite extraer datos de arreglos u objetos usando una sintaxis que se asemeja a la contrucción de arreglos o objetos
literales.
// sin destructuración
var uno = foo[0];
var dos = foo[1];
var tres = foo[2];
// con destructuración
var [uno, dos, tres] = foo;
Operadores de comparación
Un operador de comparación compara sus operandos y devuelve un valor lógico en función de si la comparación es
verdadera (true) o falsa (false). Los operadores pueden ser númericos, de cadena de caracteres (Strings), lógicos o de
objetos. Las cadenas de caracteres son comparadas basándose en un orden lexicográfico estándar, usando valores
Unicode. En la mayoría de los casos, si los dos operandos no son del mismo tipo, JavaScriptintenta convertirlos en el tipo
apropiado para permitir la comparación, generalmente esta conversión se realiza de manera numérica. Las únicas
excepciones que tiene esta conversión son los operadores === y !== que ejecutan comparaciones de igualdad o
desigualdad de manera estricta (chequeando si ambos operandos son del mismo tipo). Estos operadores no intentan
convertir los operandos a un tipo compatible antes de comprobar su igualdad. La siguiente tabla describe los operadores
de comparación en base al siguiente código de ejemplo:
var var1 = 3;
var var2 = 4;
Estrictamente Devuelve true si los operandos son igual y tienen el mismo tipo. Mira 3 === var1
iguales (===) también Object.is y sameness in JS.
Estrictamente Devuelve true si los operandos no son iguales y/o no son del mismo var1 !== "3"
desiguales (!==) tipo. 3 !== "3"
Tabla 3.2 Operadores de comparación
Ejemplos
Operador Descripción
devolviendo true
Devuelve true si el operando de la izquierda es mayor que el var2 > var1
Mayor que (>)
operando de la derecha. "12" > 2
Operadores aritméticos
Los operadores aritméticos toman los valores númericos (tanto literales como variables) de sus operandos y devuelven un
único resultado numérico. Los operadores aritméticos estandar son la suma (+), la resta (-), la multiplicación (*) y la
división (/). Estos operadores funcionan como en la mayoría de los lenguajes de programación cuando son usados con
números de coma flotante (en particular, tenga en cuenta que la división por cero produce Infinity). Por ejemplo:
1 / 2; // 0.5
1 / 2 == 1.0 / 2.0; // es true
Además de las operaciones de aritmética estándar (+, -, * y /), JavaScript brinda los siguientes operadores aritméticos
descritos en la tabla:
Tabla 3.3 Operadores aritméticos
Operador Descripción Ejemplo
Operador binario correspondiente al módulo de una
operación. Devuelve el resto de la división de dos
Resto (%) operandos. 12 % 5 devuelve 2.
Devuelve uno por cada posición de bit en la cual al menos uno de los bits
OR bit a bit a | b correspondientes de ambos operandos tiene valor uno.
Los operandos son convertidos a enteros de 32 bits y expresados como series de bits (ceros y unos). Se
descartarán los bits más relevantes de los números con más de 32 bits. Por ejemplo el siguiente entero con más de 32 bits
será convertido a un entero de 32 bits:
Antes: 11100110111110100000000000000110000000000001
Después: 10100000000000000110000000000001
Cada bit en el primer operando es emparejado con el correspondiente bit en el segundo operando: el primer bit del
primer operando con el primer bit del segundo operando, el segundo bit del primer operando con el segundo bit del
segundo operando y así consecutivamente.
La operación se aplica a cada par de bits y el resultado es construido bit a bit.
Por ejemplo, la representación binaria de 9 es 1001, y la representación binaria de 15 es 1111. Cuando se le aplican a estos
valores las operaciones bit a bit, los resultados son los siguientes:
Tabla 3.5 Ejemplo de operadores bit a bit
Expresión Resultado Descripción binaria
15 & 9 9 1111 & 1001 = 1001
Los operadores de desplazamiento binario utilizan dos operandos: el primero es el número que será desplazado, y el
segundo es el número de posiciones binarias que el primer operando será desplazado. La dirección del desplazamiento es
controlada por el operador utilizado.
Los operadores de desplazamiento binario convierten los operandos en enteros de 32 bits y retornarán un resultado que
será del mismo tipo que el operando de la izquierda
Desplazamiento a la Este operador desplaza hacia la derecha la 9>>2 retorna 2, puesto que la representación binaria
derecha con representación binaria del primer operando. de 9 es 1001 y al ser desplazada 2 posiciones de
propagación de La cantidad de posiciones de bits bits hacia la derecha, da como resultado 10, cuya
Tabla 3.6 Operadores de desplazamiento binario
Operador Descripción Ejemplo
signo (>>) desplazadas es marcada por el segundo representación decimal es 2. Del mismo modo, -
operando. El exceso de bits desplazado a la 9>>2 retorna -3, puesto que al mantener los bits
derecha se descarta. relevantes a la izquierda, el signo se mantiene.
Desplazamiento a la Este operador desplaza hacia la derecha la 19>>>2 retorna 4, puesto que la representación
derecha con relleno representación binaria del primer operando. binaria de 19 es 10011 y al ser
de ceros (>>>) La cantidad de posiciones de bits desplazada 2posiciones de bits hacia la derecha da
desplazadas es marcada por el segundo como resultado 100, cuya representación decimal
operando. El exceso de bits desplazado a la es 4. Para números no negativos este operador
derecha se descarta, dejando ceros a la generará el mismo resultado que el de
izquierda de los bits desplazados. desplazamiento a la derecha con propagación de
signo (>>).
Operadores lógicos
Los operadores lógicos son comúnmente utilizados con valores booleanos; estos operadores devuelven un valor booleano.
Sin embargo, los operadores && y || realmente devuelven el valor de uno de los operandos, asi que si estos operadores
son usados con valores no booleanos, podrían devolveran un valor no booleano. En la siguiente tabla se describen los
operadores lógicos:
Tabla 3.6 Operadores lógicos
Operador Uso Descripción
AND expr1 && Devuelve expr1 si puede ser convertido a false de lo contrario devuelve expr2. Por lo tanto,
Lógico (&&) expr2 cuando se usa con valores booleanos, && devuelve true si ambos operandos son true, en caso
contrario devuelve false.
NOT !expr Devuelve false si su operando puede ser convertido a true, en caso contrario, devuelve true.
Lógico(!)
Ejemplos de expresiones que pueden ser convertidas a false son aquellas que pueden ser evaluadas
como null, 0, NaN, undefined o una cadena vacía.
El siguiente código muestra ejemplos del operador && (AND Lógico).
Como las expresiones lógicas son evaluadas de izquierda a derecha, estas son evaluadas de manera mínima (también
llamada de circuito corto) usando las siguientes reglas:
La versión acortada de este operador de asignación (+=) puede ser usada también para concatenar cadenas de
caracteres.
Por ejemplo,
Si la condición es true, el operador tomará el valor1, de lo contrario tomará el valor2. Puedes usar el operador condicional
en cualquier lugar que use un operador estándar.
Por ejemplo,
Esta sentencia asigna el valor adulto a la variable estado si edad es mayor o igual a 18, de lo contrario le asigna el
valor menor.
Operador coma
El operador coma (,) simplemente evalúa ambos operandos y retorna el valor del último. Este operador es ante todo
utilizado dentro de un ciclo for, permitiendo que diferentes variables sean actualizadas en cada iteración del ciclo.
Por ejemplo, si a es un Array bi-dimensional con 10 elementos en cada lado, el siguiente código usa el operador coma
para actualizar dos variables al mismo tiempo. El código imprime en la consola los valores correspondientes a la diagonal
del Array:
for (var i = 0, j = 9; i <= j; i++, j--)
console.log("a[" + i + "][" + j + "]= " + a[i][j]);
Operadores unarios
Una operación unaria es una operación que sólo necesita un operando.
delete
La función del operador delete es eliminar un objeto, una propiedad de un objeto, o un elemento en el indice específico de
un Array. La sintaxis es la siguiente:
delete nombreObjeto;
delete nombreObjeto.propiedad;
delete nombreObjeto[indice];
delete propiedad; // solo admitido con una declaración "with"
x = 42;
var y = 43;
miObj = new Number();
miObj.h = 4; // crea la propiedad "h"
delete x; // devuelve true (se puede eliminar si se declaró implícitamente)
delete y; // devuelve false (no se puede eliminar si se declaró con var)
delete Math.PI; // devuelve false (no se pueden eliminar propiedades predefinidas)
delete miObj.h; // devuelve true (se pueden eliminar propiedades definidas por el usuario)
delete miObj; // devuelve true (se puede eliminar si se ha declarado implícitamente)
Si desea que un elemento de un Array exista pero su valor sea undefined, debe asignarle el valor undefined en vez de usar
el operador delete. En el siguiente ejemplo a arboles[3] se le asigna el valor undefined, pero el elemento seguirá existiendo
El operador typeof devuelve una cadena de caracteres indicando el tipo del operando evaluado. En los ejemplos
anteriores operando hace referencia a la cadena de caracteres, variable, palabra clave u objeto del que se intenta obtener
su tipo. Los paréntesis son opcionales.
Supón que defines las siguientes variables:
Con los números o las cadenas de caracteres, el operador typeof devuelve los siguientes resultados:
En el caso de que se utilice como operando una propiedad, el operador typeof devolverá el tipo de dicha propiedad:
El operador void especifica una expresión que será evaluada y no retornará ningún resultado. En los ejemplos
anteriores, expresion hace referencia a la expresión que será evaluada. Si bien los paréntesis que envuelven a la expresión
son opcionales, en cuanto a estilo del código, es una buena práctica usarlos.
El operador void puede ser usado para especificar una expresión como un link de hipertexto. La expresión será evaluada
pero no cargará una página en el documento actual.
El siguiente código crea un link de hipertexto que no hace nada cuando el usuario hace click en él. Cuando el usuario hace
click sobre el link, void(0) será evaluada como undefined, lo cual no tiene efecto en JavaScript.
El siguiente código crea un link de hipertexto que envía un formulario cuando el usuario hace click en él.
<a href="javascript:void(document.form.submit())">
Haz click para enviar</a>
Operadores relacionales
Un operador relacional compara sus operandos y retorna un valor booleano basado en si la comparación es verdadera.
in
El operador in devuelve true si la propiedad especificada como primer operando se encuentra en el objeto especificado
como segundo operando. La sintaxis es:
nombrePropiedadoNumero in nombreObjeto
Donde nombrePropiedadoNumero es una cadena o expresión numérica que representa un nombre de propiedad o índice de
matriz y nombreObjeto es el nombre de un objeto.
Los siguientes ejemplos muestran algunos usos del operador in.
// Arrays
var arboles = new Array("secoya", "laurel", "cedro", "roble", "arce");
0 in arboles; // devuelve true
3 in arboles; // devuelve true
6 in arboles; // devuelve false
"laurel" in arboles; // devuelve false (Se debe especificar el número de índice,
// no el valor contenido en ese índice)
"length" in arboles; // devuelve true (length es una propiedad del Array)
// Objetos predefinidos
"PI" in Math; // devuelve true
var miCadena = new String("coral");
"length" in miCadena; // devuelve true
// Objetos creados
var miCoche = {marca: "Honda", modelo: "Accord", fecha: 1998};
"marca" in miCoche; // devuelve true
"modelo" in miCoche; // devuelve true
instanceof
El operador instanceof devuelve true si el objeto especificado como primer operando es del tipo de objeto especificado
como segundo parámetro. La sintaxis es:
nombreObjeto instanceof tipoObjeto
Donde nombreObjeto es el nombre del objeto que se desea comparar y tipoObjeto es un tipo de objeto, como Date o Array.
Utilice instanceof cuando necesite confirmar el tipo de un objeto en tiempo de ejecución. Por ejemplo, al captar
excepciones, puede derivarse a un código de manejo de excepciones diferente dependiendo del tipo de excepción
lanzada.
Por ejemplo, el código siguiente utiliza instanceof para determinar si elDia es un objeto de tipo Date. Y debido a
que elDia es un objeto Date, las sentencias en la sentencia if se ejecutarán.
Precedencia de operadores
La precedencia de operadores determina el orden en que estos son aplicados cuando se evalúa una expresión. Esta
precedencia puede ser alterada usando paréntesis.
La siguiente tabla describe la precedencia de operadores, de mayor a menor importancia.
multiplicación / división * / %
adición / sustracción + -
Tabla 3.7 Precedencia de operadores
Tipo de operador operadores individuales
desplazamiento binario << >> >>>
XOR binario ^
OR binario |
OR lógico ||
condicional ?:
coma ,
Una versión más detallada de esta lista, completa y con links a detalles adicionales acerca de cada operador, puede
encontrarse en Referencia de JavaScript.
Expresiones
Una expresión es cualquier unidad válida de código que resuelve un valor.
Cada expresión sintáctica válida resuelve a algún valor, pero conceptualmente, hay dos tipos de expresiones: las que
tienen efectos secundarios (por ejemplo: aquellas que asignan un valor a una variable) y las que de alguna manera son
evaluadas y resuelven un valor.
La expresión x = 7 es un ejemplo del primer tipo. Esta expresión usa el operador = para asignar el valor siete a la
variable x. La expresión en sí misma evalúa a siete.
El código 3 + 4 es un ejemplo del segundo tipo de expresiones. Esta expresión usa el operador + para sumar tres y cuatro
sin asignar el valor (siete) a ninguna variable.
JavaScript cuenta con las siguientes categorías de expresiones:
Aritméticas: evalúan a un número, por ejemplo 3.14159. (Usos generales Operadores aritméticos.)
Cadenas de caracteres: evalúan a una cadena de caracteres, por ejemplo, "Juan" o "234". (Usos
generales Operadores de cadenas de caracteres.)
Lógicas: evalúan a true o false. (A menudo involucran a los Operadores lógicos.)
Expresiones primarias: Palabras clave básicas y expresiones generales en JavaScript.
Expresiones al lado izquierdo: Los valores izquierdos son el destino de una asignación.
Expresiones primarias
Son palabras claves básicas y expresiones generales en JavaScript.
this
Use esta palabra reservada this para referirse al objeto actual. En general, this hace referencia al objeto llamador en un
método. Se usa de la siguiente manera:
this["nombreDePropiedad"]
this.nombreDePropiedad
Ejemplo 1:
Supongamos una función llamada validate que valida la propiedad value de un objeto, dado un objeto y dos
valores, lowval y hival, como extremos de un rango.
Puedes invocar a esta función validate para cada evento onChange de los elementos de un formulario, utilizando this para
pasar el campo del formulario como elemento a validar. Por ejemplo:
Ejemplo 2:
Cuando es combinada con la propiedad form, this puede hacer referencia al formulario padre del elemento actual. En el
siguiente ejemplo, el formulario miFormulario contiene un elemento input de tipo text y un elemento input de tipo button.
Cuando el usuario hace clic en el botón, se le asigna el nombre del formulario al input de tipo text. El evento onClick del
botón usa this.form para hacer referencia al formulario padre, miFormulario.
<form name="miFormulario">
Nombre del formulario:
<input type="text" name="text1" value="Beluga"/>
<input type="button" name="button1" value="Mostrar nombre del formulario"
onClick="this.form.text1.value = this.form.name;"/>
</form>
Operador de agrupación
El operador de agrupación ( ) controla la precedencia de la evaluación en las expresiones. Por ejemplo, puedes cambiar
el orden de la multiplicación y la división antes de la suma y la resta para que se evalúe la suma primero:
var a = 1;
var b = 2;
var c = 3;
// lo cual es equivalente a
a * c + b * c // 9
new
Utilice el operador new para crear una instancia de un tipo propio o de uno de los tipos de objetos
predefinidos: Array, Boolean, Date, Function, Image, Number, Object, Option, RegExp o String. La semántica es la siguiente:
Operador de propagación
El operador de propagación permite que una expresión sea expandida en situaciones donde se esperan múltiples
argumentos (para llamadas a funciones) o múltiples elementos (para Arrays literales).
Ejemplo:
Hoy, si tienes un Array y deseas crear un nuevo Array que contenga también los elementos del primero, la sintaxis de
un Array literal no es suficiente y debes recurrir a piezas de código que hagan uso de métodos como push, splice, concat,
etc. Con la sintaxis de propagación esto se convierte en algo mucho más simple:
var partes = ["hombros", "rodillas"];
var letra = ["cabeza", ...partes, "y", "dedos"];
function f(x, y, z) { }
var args = [0, 1, 2];
f(...args);
Funciones
Definición de funciones
Declaraciones de función
La definición de una función (también llamada declaración de función o sentencia de función) consiste de la palabra
clave (reservada) function, seguida por:
El nombre de la función (opcional).
Una lista de argumentos para la función, encerrados entre paréntesis y separados por comas (,).
Las sentencias JavaScript que definen la función, encerradas por llaves, { }.
Por ejemplo, el siguiente código define una función simple llamada square:
function square(number) {
return number * number;
}
La función square toma un argumento, llamado number. La función consiste de una sentencia que expresa el retorno del
argumento de la función (el cual es, number) multiplicado por sí mismo. La sentencia return especifica el valor retornado por
la función.
Los parámetros primitivos (como puede ser un número) son pasados a las funciones por valor; el valor es pasado a la
función, si la función cambia el valor del parámetro, este cambio no es reflejado globalmente o en otra llamada a la
función.
Si pasa un objecto (p. ej. un valor no primitivo, como un Array o un objeto definido por el usuario) como parámetro, y la
función cambia las propiedades del objeto, este cambio sí es visible desde afuera de la función, como se ve en el siguiente
ejemplo:
function myFunc(theObject) {
theObject.make = 'Toyota';
}
myFunc(mycar);
y = mycar.make; // y toma el valor "Toyota"
// (la propiedad make fue cambida por la funcion)
Nota: Tenga en cuenta que asignar un nuevo objeto al parámetro no tendrá ningún efecto fuera de la función, porque esto
está cambiando el valor del parámetro en lugar de una de las propiedades del objeto:
function myFunc(theObject) {
theObject = {make: 'Ford', model: 'Focus', year: 2006};
}
myFunc(mycar);
y = mycar.make; // y sigue con el valor "Honda"
Expresiones de función
Si bien la declaración de la función anterior es sintácticamente una sentencia, las funciones pueden también ser creadas
por una expresión de función. Tal función puede ser anónima; no debe tener un nombre. Por ejemplo, la
función square podría haber sido definida como:
var square = function(number) {return number * number};
var x = square(4) //x obtiene el valor 16
Sin embargo, se puede proporcionar un nombre a una expresión de función, y éste puede ser utilizado dentro de la función
para referirse a sí misma, o en un depurador para identificar la función en el trazado de pila:
print(factorial(3));
Las expresiones de función son convenientes cuando se pasa una función como argumento a otra función. El siguiente
ejemplo muestra una función map siendo definida y luego llamada con una expresión de función como primer parámetro:
function map(f,a) {
var result = [], // Crea un nuevo Array
i;
for (i = 0; i != a.length; i++)
result[i] = f(a[i]);
return result;
}
El siguiente código:
En JavaScript, una función puede ser definida en base a una condición. Por ejemplo, la siguiente definición de
función myFunc es definida sólo si num es igual a 0:
var myFunc;
if (num == 0){
myFunc = function(theObject) {
theObject.make = "Toyota"
}
}
Además de definir funciones como se describe aquí, se puede utilizar el constructor Functionpara crear funciones desde
una cadena en tiempo de ejecución, muy al estilo de eval().
Un método, es una función que es propiedad de un objeto. Puede leer más acerca de objetos y métodos en Trabajando
con objetos.
Llamando funciones
Definir una función no la ejecuta. Definir una función simplemente la nombra y especifica que hacer cuando la función es
llamada. Llamar la función es lo que realmente realiza las acciones especificadas con los parámetros indicados. Por
ejemplo, si define la función square, podría llamarla como sigue:
square(5);
La sentencia anterior llama a la función con el argumento 5. La función ejecuta sus sentencias y retorna el valor 25.
Las funciones deben de estar dentro del ámbito cuando son llamadas, pero la declaración de la función puede ser izada
(aparecer por debajo de la llamada en el codigo), como muestra el siguiente ejemplo:
console.log(square(5));
/* ... */
function square(n) { return n*n }
El ámbito de la función es la función en la que es declarada o el programa entero si ésta es declarada en el nivel superior.
Nota: Esto sólo funciona cuando se define la función utilizando la sintaxis anterior (p.ej. function funcName(){}). El
siguiente código no funcionará. Esto quiere decir que el izado de funciones sólo funciona con una declaración de función y
no con una expresión de función
Los argumentos de una función no están limitados a cadenas y números. Pueden enviarse objetos enteros a una función.
La función show_props() (definida en Trabajando con objetos) es un ejemplo de una función que toma un objeto como
argumento.
Una función puede ser recursiva; es decir, que puede llamarse a sí misma. Por ejemplo, a continuación tenemos una
función que calcula el factorial de forma recursiva:
function factorial(n){
if ((n == 0) || (n == 1))
return 1;
else
return (n * factorial(n - 1));
}
Entonces, podría calcular los factoriales desde uno hasta cinco de la siguiente manera:
var a, b, c, d, e;
a = factorial(1); // a obtiene el valor 1
b = factorial(2); // b obtiene el valor 2
c = factorial(3); // c obtiene el valor 6
d = factorial(4); // d obtiene el valor 24
e = factorial(5); // e obtiene el valor 120
Hay otras formas de llamar a las funciones. A menudo hay casos en donde una función necesita ser llamada de forma
dinámica, o en donde el número de argumentos de la misma varía; o en la cual, el contexto de la llamada de la función
necesita ser ajustada para un objeto específico determinado en el tiempo de ejecución. Resulta que las funciones en sí
mismas son objetos, y estos objetos a su vez tienen métodos (ver el objeto Function). Uno de éstos, el método apply(), se
puede utilizar para lograr este objetivo.
Ámbito de una Función
Las variables definidas dentro de una función no pueden ser accedidas desde ningún lugar fuera de la función, ya que la
variable está definida sólo en el ámbito de la función. Sin embargo, una función puede acceder a todas las variables y
funciones definidas dentro del ámbito en el cual está definida. En otras palabras, una función definida en el ámbito global
puede acceder a todas las variables definidas en el ámbito global. Una función definida dentro de otra función, también
puede acceder a todas las variables definidas en su función padre y a cualquier otra variable a la que la función padre
tenga acceso.
multiplicar(); // Retorna 60
function agregar() {
return nombre + " puntaje " + (num1 + num2);
}
return agregar();
}
1. El nombre de la función
2. arguments.callee
3. Una variable en el ámbito en el que se refiere a la función
Por ejemplo, considere la siguiente definición de función:
1. bar()
2. arguments.callee()
3. foo()
Una función que se llama a sí misma se denomina una función recursiva. En cierto modo, la recursividad es análoga a un
bucle. Ambos ejecutan el mismo código varias veces, y ambos requieren una condición (para evitar un bucle infinito, o más
bien, la recursividad infinita en este caso). Por ejemplo, el siguiente bucle:
var x = 0;
while (x < 10) { // "x < 10" es la condicion del bucle
// hacer cosas
x++;
}
Sin embargo, algunos algoritmos no pueden ser bucles iterativos simples. Por ejemplo, obtener todos los nodos de una
estructura de árbol (p. ej. el DOM) es más fácil utilizando recursividad:
function walkTree(node) {
if (node == null) //
return;
// hacer alguna cosa con el nodo
for (var i = 0; i < node.childNodes.length; i++) {
walkTree(node.childNodes[i]);
}
}
En comparación con la función loop (definida anteriomente), aquí (en el ejemplo walkTree) cada llamada recursiva a sí
misma, hace muchas llamadas recursivas.
Es posible convertir cualquier algoritmo recursivo a uno no-recursivo, pero a menudo la lógica es mucho más compleja y
hacerlo requiere el uso de una pila. De hecho, la recursividad en sí misma utiliza una pila: la pila de la función.
function foo(i) {
if (i < 0)
return;
console.log('inicio:' + i);
foo(i - 1);
console.log('final:' + i);
}
foo(3);
// Salida:
// inicio:3
// inicio:2
// inicio:1
// inicio:0
// final:0
// final:1
// final:2
// final:3
En resumen:
La función interna sólo se puede acceder a partir de sentencias dentro de la función externa.
La función interna forma un cierre: la función interna puede utilizar los argumentos y variables de la función externa,
mientras que la función externa no puede utilizar los argumentos y las variables de la función interna.
El siguiente ejemplo muestra funciones anidadas:
function addSquares(a,b) {
function square(x) {
return x * x;
}
return square(a) + square(b);
}
a = addSquares(2,3); // retorna 13
b = addSquares(3,4); // retorna 25
c = addSquares(4,5); // retorna 41
Dado que la función interna forma un cierre, se puede llamar a la función externa y especificar argumentos para ambas,
tanto para la función externa como para la interna:
function outside(x) {
function inside(y) {
return x + y;
}
return inside;
}
fn_inside = outside(3); // Pensar en esto como: dar una funcion que suma 3 a lo que sea que des
result = fn_inside(5); // retorna 8
Preservación de variables
Observa cómo x se conserva cuando inside es retornada. Un cierre debe preservar los argumentos y variables dentro de
todos los ámbitos que referencía. Dado que cada llamada proporciona potencialmente diferentes argumentos, un nuevo
cierre es creado para cada llamada a outside. La memoria puede ser liberada sólo cuando la (función) insideretornada ya
no es accesible.
Esto no es diferente de almacenar referencias en otros objetos, pero a menudo es menos evidente porque uno no
establece las referencias directamente y no puede inspeccionarlas.
Funciones Multi-anidadas
Las funciones pueden ser multi-anidadas, p. ej una función (A) que contiene una función (B) que contiene una función (C).
Aqui ambas funciones B y C forman cierres, así que B puede acceder A, y C puede acceder B. Además, dado que C
puede acceder B, la cual puede acceder A, entonces C puede también acceder A. En consecuencia, los cierres pueden
contener múltiples ámbitos; que contienen de forma recursiva el ámbito de las funciones que los contienen. Esto se conoce
como encadenamiento de ámbito. (¿Por qué se le llama "encadenamiento" se explicará más adelante.)
Considere el siguiente ejemplo:
function A(x) {
function B(y) {
function C(z) {
console.log(x + y + z);
}
C(3);
}
B(2);
}
A(1); // registra 6 (1 + 2 + 3)
Conflictos de nombres
Cuando dos argumentos o variables en los ámbitos de un cierre tienen el mismo nombre, ocurre un conflicto de nombre.
Los ámbitos más internos toman precedencia, asi que el ambito más interno de todos toma la precedencia más alta,
mientras que el ámbito más externo toma la más baja. Esta es la cadena de ámbito. El primero en la cadena es el ámbito
más interno de todos, y el último, es el ámbito más externo. Considere lo siguiente:
function outside() {
var x = 10;
function inside(x) {
return x;
}
return inside;
}
result = outside()(20); // retorna 20 en lugar de 10
var pet = function(name) { // La funcion externa define una variable llamada "name"
var getName = function() {
return name; // La funcion interna tiene aceso a la variable "name" de la
funcion externa
}
Esto puede ser mucho más complejo que el código anterior. Puede ser retornado un objeto que contiene métodos para
manipular las variables internas de la función externa.
return {
setName: function(newName) {
name = newName;
},
getName: function() {
return name;
},
getSex: function() {
return sex;
},
setSex: function(newSex) {
if(typeof newSex == "string" && (newSex.toLowerCase() == "male" || newSex.toLowerCase() ==
"female")) {
sex = newSex;
}
}
}
}
pet.setName("Oliver");
pet.setSex("male");
pet.getSex(); // male
pet.getName(); // Oliver
En el código anterior, la variable name de la función externa es accesible desde las funciones internas, y no hay otra forma
de acceder a las variables internas excepto a través de las funciones internas. Las variables internas de las funciones
internas actúan como almacenamientos seguros para las variables y argumentos externos. Mantienen "persistente", y aún
segura, la información con la que necesitan trabajar las funciones internas. Las funciones incluso no tienen por que ser
asignadas a una variable, o tener un nombre.
return function () {
return secureCode;
};
})();
getCode(); // Retorna el codigo secreto
Hay, sin embargo, una serie obstáculos a vigilar cuando se usan clausuras. Si una función encerrada define una variable
con el mismo nombre que una variable dentro del ámbito exterior, no hay forma referirse de nuevo a la variable del ámbito
exterior.
var createPet = function(name) { // la funcion externa define una variable llamada "name"
return {
setName: function(name) { // la funcion encerrada tambien define una variable llamada "name"
name = name; // ¿¿¿ Como accedemos la "name" definida por la funcion
externa ???
}
}
}
La variable mágica this es muy tramposa en las clausuras. Deben de ser usadas cuidadosamente (las clausuras que
usan this), el modo en que this se refiere depende completamente de en donde la función fue llamada, en lugar de en
donde fue definida.
Un excelente y elaborado artículo sobre closures puede encontrarse aqui.
Usando el objeto arguments
Los argumentos de una función son mantenidos en un objeto similar a un array. Dentro de una función, los argumentos
pasados a la misma pueden ser direccionados de la siguiente forma:
arguments[i]
donde i es el número ordinal del argumento, comenzando desde cero. Entonces, el primer argumento pasado a una
función sería arguments[0]. El número total de argumentos es mostrado por arguments.length.
Usando el objeto arguments, se puede llamar una función con más argumentos de los que formalmente fueron declarados
que puede aceptar. Esto es a menudo muy útil cuando no se sabe con antelación cuantos argumentos serán pasados a la
función. Se puede usar arguments.length para determinar el número de argumentos realmente pasados a la función, y
luego acceder a cada argumento usando el objeto arguments.
Por ejemplo, consideremos una función que concatena varias cadenas de caracteres (strings). El único argumento formal
para la función es una string que especifica los caracteres que separan los elementos a concatenar. La función es definida
de la siguiente forma:
function myConcat(separator) {
var result = "", // initialize list
i;
// iterate through arguments
for (i = 1; i < arguments.length; i++) {
result += arguments[i] + separator;
}
return result;
}
Se pueden pasar cualquier número de argumentos a esta función, y la misma concatenará cada argumento en una "lista"
de strings:
Nota: La variable arguments es de "estilo array", pero no es un array. Es similar a un array por poseer un índice numérico
(index) y una propiedad length. Sin embargo, no posee todos los métodos de manipulación propios de un array.
function multiply(a, b) {
b = typeof b !== 'undefined' ? b : 1;
return a*b;
}
multiply(5); // 5
Con los parámetros por defecto, la comprobación en el cuerpo de la función ya no es necesaria. Ahora, puede
simplemente poner 1 como valor por defecto para b en la cabeza de la función.
function multiply(a, b = 1) {
return a*b;
}
multiply(5); // 5
Funciones flecha
Una expresión de función flecha (también conocida como función flecha gruesa o fat arrow function en inglés) tiene
una sintaxis más corta comparada con las expresiones de función y not tiene su
propio this, arguments, super o new.target. Las funciones flecha son siempre funciones anónimas. Véase también esta
entrada en el blog hacks.mozilla.org : "ES6 In Depth: Arrow functions" (en inglés).
Dos factores influenciaron la introdución de las funciones flecha: funciones más cortas y el léxico this.
Funciones más cortas
En algunos patrones funcionales, las funciones más cortas son bienvenidas. Compare:
var a = [
"Hydrogen",
"Helium",
"Lithium",
"Beryllium"
];
Sin propio this
Hasta antes de las funciones flecha, cada nueva función definía su propio valor this (un nuevo objecto en el caso de un
constructor, no definido en llamada a funciones en modo estricto, el objeto de contexto si la funcion es llamada como un
"metodo de objeto", etc.). Esto probó ser molesto en un estilo de programación orientada a objetos.
function Person() {
setInterval(function growUp() {
// En modo no estricto, la funcion growUp() define `this`
// como el objeto global, el cual es diferente de el `this`
// definido por el constructor Person().
this.age++;
}, 1000);
}
var p = new Person();
En ECMAScript 3/5, esto fue solucionado asignado el valor contenido por this a una variable sobre la que se podía cerrar
(o clausurar).
function Person() {
var self = this; // Algunos eligen `that` en lugar de `self`.
// Elija uno y sea consistente.
self.age = 0;
setInterval(function growUp() {
// La retrollamada se refiere a la variable `self` de la cual
// el valor es el objeto esperado.
self.age++;
}, 1000);
}
Alternativamente, una función ligada podría ser creada de modo que el propio valor de thissería pasado a la
función growUp().
Las funciones flecha capturan el valor de this del contexto circundante, por lo que el siguiente código funciona como se
espera.
function Person(){
this.age = 0;
setInterval(() => {
this.age++; // |this| se refiere apropiadamente al objeto instancia de Person.
}, 1000);
}
var p = new Person();
Funciones predefinidas
JavaScript tiene varias funciones predefinidas de nivel superior:
eval
isFinite
isNaN
parseInt and parseFloat
Number and String
encodeURI, decodeURI, encodeURIComponent, and decodeURIComponent (all available with Javascript 1.5 and
later).
Las siguientes secciones presentan estas funciones. Vea la Refencia JavaScript para obtener información detallada sobre
todas estas funciones.
Método eval
El método eval() evalúa el código JavaScript representado como una cadena de caracteres (string). La sintaxis de eval es:
donde string es la cadena de caracteres a ser evaluada. que puede representar una expresión, sentencia o secuencia de
sentencias de JavaScript. La expresión puede incluir variables y propiedades de un objeto existente.
Si la cadena representa una expresión, eval() la evalúa como una expresión. Si el argumento representa una o más
sentencias de JavaScript, eval() ejecuta las sentencias. El ámbito de aplicación de código eval es idéntico al alcance del
código de llamada. No llame a eval para evaluar una expresión aritmética; JavaScript evalúa las expresiones aritméticas
automáticamente.
Funcion global isFinite
La función global isFinite determina si el valor pasado es un número finito, si se necesita el parámetro primero es
convertido a número. La sintaxis de isFinite es:
isFinite(number);
if(isFinite(ClientInput)){
/* tomar pasos espeficos */
}
Funcion isNaN
La función isNaN evalúa un argumento para determinar si es "NaN" (no es un número). La sintaxis de isNaN es:
isNaN(testValue);
if (isNaN(floatValue)) {
notFloat();
} else {
isFloat();
}
Funciones parseInt and parseFloat
Las dos funciones "parse", parseInt y parseFloat, devuelven un valor numérico cuando se les da una cadena como
argumento.
La sintaxis de parseFloat es:
parseFloat(str);
parseInt(str [, radix]);
parseInt analiza su primer argumento, la cadena str, e intenta devolver un entero de la base especificada, indicada por el
segundo, el argumento opcional, radix. Por ejemplo, un radix de diez indica a convertir en un número decimal, ocho octal,
hexadecimal dieciséis, y así sucesivamente. Para bases superiores a diez, las letras del alfabeto indican numerales
mayores de nueve. Por ejemplo, para los números hexadecimales (base 16),de A a F se utilizan.
Si parseInt encuentra un carácter que no es un número en la base especificada, lo ignora y todos los carácteres sucesivos
y devuelve el valor entero analizado hasta ese momento. Si el primer carácter no puede ser convertido a un número en la
base especificada, devuelve "NaN". La función parseInt trunca la cadena a valores enteros.
Funciones Number y String
Las funciones Number y String le permiten convertir un objeto a un número o una cadena. La sintaxis de estas funciones
es:
var objRef;
objRef = Number(objRef);
objRef = String(objRef);
escape(string);
unescape(string);
Estas funciones son usadas principalmente en javascript del lado del servidor para codificar y decodificar pares
nombres/valores en URLs.